2012-07-29 41 views
25

aynı değer noktaya stil için birden fazla işlevi uygulama Bir gün bıktım ve beynimi egzersiz istedim, bu yüzden ben 99 Haskell Problems yapmaya karar verdim, ancak kendimi sınırsız bir tarzda yapmak için sınırlı. Noktasız stilde işler yaparken çok fazla kırpılan bir problem şudur: Her bir sonucu bağımsız bir varlık olarak tutarken aynı değere birden çok işlevi nasıl uygularsınız?Haskell

foobar x = [id x, reverse x] 

Ve ne şike serbest gösterimde bugüne kadar ile geldim: Sivri gösterimi kullanılarak

foobar' = `map` [id, reverse] ($ x) 

orada sonuna kapalı x olsun gibi olamaz.

cevap

25

Diğerleri zaten Reader monad kullanarak bunu nasıl gönderdiniz, ama bu sadece bir yol değil. İkinci işlevinizin oldukça yakın olduğu ortaya çıkıyor. Sana x bir sağdaki konuma yakın, neredeyse geldin zaten olduğundan

foobar' x = (`map` [id, reverse]) ($ x) 

yayınlamak istemiştim düşünüyorum.

-- by the definition of a right operator section 
foobar'2 x = (`map` [id, reverse]) (\y -> ($) y x) 

Sonraki x

fonksiyonu kapsamına yeni bir değişken getiren ve uygulayarak lambda vücuttan x kaldırın: o çalışmak için biraz daha kolay olduğu için Birincisi, bir işlev haline bölüm ($ x) dönüşümü
-- lambda abstraction I think... 
foobar'2 x = (`map` [id, reverse]) $ (\z y -> ($) y z) x 
bir işlev bileşim olarak, bu uygulama yeniden

ve sonra eta azaltabilir:

-- by definition of '.' 
foobar'3 x = (`map` [id, reverse]) . (\z y -> ($) y z) $ x 

-- eta reduction 
foobar'4 = (`map` [id, reverse]) . (\z y -> ($) y z) 

Son olarak, bir fonksiyonun

-- by definition of `flip` 
foobar'5 = (`map` [id,reverse]) . flip ($) 

ile lambda yerini alabilir fark ve bir nokta içermeyen formu var.

8

Sen okuyucu monadın Applicative örneği ilgi duyabilecek: Her iki almak, hangi

liftA2 (+) sin cos 3 
İşte

sin ve cos işlevler şunlardır: kolayca bir tartışmayı dağıtabilir bunu kullanma

instance Applicative (e ->) 

Değer 3. Tek tek sonuçlar daha sonra (+) kullanılarak birleştirilir. Bunu,(->) örneğiyle birleştirebilirsiniz, ancak (.) ve id'un özel özelleştirilmiş sürümleri Prelude'da zaten tanımlanmıştır.

Arka plan: (e ->) için Applicative örneği alınarak (<*>)S combinator ve pureK combinator kayak taşı temsil eder. Bu değer x ((fx) (gx) bağımlı hem de fonksiyonu uygulaması (fg) alır ve yapar

S f g x = f x (g x) 

: S tam iki fonksiyon için bir bağımsız değişken dağıtmak için kullanılır).

9

Kullanım sequence:

> let foobar' = sequence [id, reverse] 
> foobar' "abcde" 
["abcde","edcba"] 
+0

. Bu, tüm kullanımlar için işe yaramaz. –

+0

@ ThomasM.DuBuisson: Hangi kısıtlamalar? –

+0

@BenMillwood Tipeclass kısıtlamalarını belirtiyorum. JohnL'un cevabı, tür a -> [a] 'dır. Bu cevap güzel ve temizken, Monad ((a -> a) => a -> [a] 'dır. –

5

Tekrar tekrar açılan birkaç basit deyimsel kombinator vardır ve bunlar daha yüksek konseptler ve kütüphanelerle yeniden yapılandırılır, ancak bunlar oldukça basittir. İsimler değişebilir ve bazıları diğerlerinden açısından uygulanabilir şunlardır:

Tabii uncurry f (x,y) == f x y Of
fork (f,g) x = (f x, g x)    -- == (f &&& g) 
prod (f,g) x = (f $ fst x, g $ snd x) -- == (f *** g) 
pmap f (x,y) = (f x, f y)    -- == (f *** f) 
dup  x = (x,x) 

vs. Bunları da bir sürü kullanılan alır.

&&& ve ***first ve second yanı sıra, Control.Arrow tanımlanmıştır. Sonra prod (f,id) == first f, prod(id,g) == second g vs vs

Yani senin foobar ayrıca Control.Monad ve Control.Monad.Instances ithalat gerekir sonuncusu için

foobar = (\(a,b)->[a,b]) . fork (id,reverse) 
     = (\(a,b)->[a,b]) . (id &&& reverse) 
     = (\(a,b)->[a,b]) . (id *** reverse) . dup 
     = join $ curry ((\(a,b)->[a,b]) . second reverse) 

olur. Ayrıca bkz. this question.


geç düzenleme: ayrıca, ertes tarafından cevap ima olarak Control.Applicative kullanarak Sınırlamalar kullanarak Tamam olursan

 = (:) <*> ((:[]) . reverse) 
+0

ayrıca, '(:) <*> (salt. reverse) '(' ((->) r), [ ] “Uygulayıcılar”, ([id, ters] <*>). Pure' ('[]' Uygulayıcı), 'sırasını [id, reverse]' ('((->) r)' Monad). –