2014-06-30 41 views
5

我在學習Haskell與Learn You a Haskell指南,我堅持在一個函數列表應用排序的例子。 Chapter 11: Functors, Applicative Functors and Monoids定義sequenceA是:函數列表上的應用排序如何工作?

sequenceA :: (Applicative f) => [f a] -> f [a] 
sequenceA [] = pure [] 
sequenceA (x:xs) = (:) <$> x <*> sequenceA xs 

我有點受sequenceA的這個例子中使用蒙羞

> sequenceA [(+3),(+2),(+1)] 3 
[6,5,4] 

我已經擴大了應用程序手動據我可以給我所相信的是正確:

(:) <$> (+3) <*> sequenceA [(+2), (+1)] 
(:) <$> (+3) <*> (:) <$> (+2) <*> (:) <$> (+1) <*> sequenceA [] 
(:) <$> (+3) <*> (:) <$> (+2) <*> (:) <$> (+1) <*> pure [] 
(:) <$> (+3) <*> (:) <$> (+2) <*> (:) <$> (+1) <*> const [] 

我看不出什麼,雖然是多麼的第二個參數sequenceA的原始應用程序,3被應用到每個部分applie d函數在列表中給出。我希望得到一些幫助,試圖圍繞評估這個聲明時所發生的事情。

+4

提示,請參閱:應用型實例'( - >)了'。編制'fmap' /'<*>'應用程序! – Xeo

回答

10

每當你處理,你需要首先確定哪些泛型類型具體類型是。在這種情況下,我們有

sequenceA :: Applicative f => [f a] -> f [a] 

應用於

[(+3),(+2),(+1)] :: Num a => [a -> a] 

換句話說,雖然這是一個有點怪異看到在第一,f成爲a ->(正確地寫入(->) a)和sequenceA這樣的類型,專門的,是

sequenceA :: Num a => [a -> a] -> a -> [a] 

哪個應該已經解釋了額外的論據來自哪裏。


那麼sequenceA如何工作?要了解,我們需要了解的Applicative實例。特別是

instance Functor ((->) a) where 
    fmap f g = f . g 

instance Applicative ((->) a) where 
    pure a' = \a -> a' 
    ff <*> fx = \a -> (ff a) (fx a) 

在這裏我們看到,(<*>)有兩個功能,產生第三。第三個函數的參數應用於每個輸入函數(這裏是fffx),然後將它們的結果應用於另一個函數。

因此在(->) a monad中的應用意味着結果的最終參數a被分配給所有的組合函數。

而這正是我們與sequenceA

sequenceA [(+3),(+2),(+1)] 
== 
\a -> [(a + 3), (a + 2), (a + 1)] 
+0

謝謝你非常有幫助的解釋,J! :)我相信我在用ghci玩了一段時間後會有一些東西: '>((:)。(+3)$ 3)(((:)。(+2)$ 3)(((:) :) (+1)$ 3)(const [] 3)))' '[6,5,4]' 儘管我必須承認,我仍然不完全理解3是如何分佈的。我看到中綴fmap運算符使得函數接受3,但我很難想象它確實發送到所有函數。也許有更好的方法來解釋它,或者如果不是,希望它有更多練習的理解。 – bpaterni

+0

也許'sequenceA'的進一步研究將會很有用。嘗試在其他應用程序或monad中查看它(「Reader」將很重要!)。用簡單的術語來說,'sequenceA'需要進行幾次有效的計算並按順序「共享」它們的效果。這樣的名字。對於功能應用順序無關緊要,但共享確實如此。 –

1

使用:

instance Applicative ((->) a) where 
    pure = const 
    (<*>) f g x = f x (g x) 

我們可以推導出:

 (:) <$> (+3) <*> (  (:) <$> (+2) <*> ( (:) <$> (+1) <*> const [])) 
pure (:) <*> (+3) <*> (pure (:) <*> (+2) <*> (pure (:) <*> (+1) <*> const [])) 
const (:) <*> (+3) <*> (const (:) <*> (+2) <*> (const (:) <*> (+1) <*> const [])) 
(const (:) <*> (+3)) <*> ((const (:) <*> (+2)) <*> ((const (:) <*> (+1)) <*> const [])) 
(const (:) <*> (+3)) <*> ((const (:) <*> (+2)) <*> ((\x -> (const (:)) x (x+1)) <*> const [])) 
(const (:) <*> (+3)) <*> ((const (:) <*> (+2)) <*> ((\x -> (:) (x+1)) <*> const [])) 
(const (:) <*> (+3)) <*> ((const (:) <*> (+2)) <*> (\y -> (\x -> (:) (x+1)) y (const [] y))) 
(const (:) <*> (+3)) <*> ((const (:) <*> (+2)) <*> (\y -> (\x -> (:) (x+1)) y [])) 
(const (:) <*> (+3)) <*> ((const (:) <*> (+2)) <*> (\y -> ((y+1):) [])) 
(const (:) <*> (+3)) <*> ((const (:) <*> (+2)) <*> (\y -> [y+1])) 
(const (:) <*> (+3)) <*> (((\x -> (const (:)) x (x+2)) <*> (\y -> [y+1])) 

(const (:) <*> (+3)) <*> (\z -> ((\x -> (const (:)) x (x+2)) z ((\y -> [y+1])z)) 
(const (:) <*> (+3)) <*> (\z -> (((const (:)) z (z+2)) ([z+1])) 
(const (:) <*> (+3)) <*> (\z -> ((z+2):) [z+1]) 
(const (:) <*> (+3)) <*> (\z -> [z+2,z+1]) 
(\x -> (const (:)) x (x+3)) <*> (\z -> [z+2,z+1]) 
(\x -> const (:) (x+3)) <*> (\z -> [z+2,z+1]) 
(\x -> ((x+3):)) <*> (\z -> [z+2,z+1]) 
\w -> (\x -> ((x+3):)) w ((\z -> [z+2,z+1]) w) 
\w -> ((w+3):) [w+2,w+1] 
\w -> [w+3,w+2,w+1] 

我敢打賭,我搞砸了一些括號