2012-12-14 74 views
5

我一直在努力通過great good書,但我正在用Applicative Functors稍微掙扎。Applicative Functors和Left from from

在以下示例中max應用於兩個Maybe函數的內容,並返回Just 6

max <$> Just 3 <*> Just 6 

爲什麼在下面的例子Left "Hello"返回,而不是要麼仿函數的內容:Left "Hello World"

(++) <$> Left "Hello" <*> Left " World" 
+0

這是傳統用法,無論是Right表示您感興趣的值,而Left表示失敗。正確的(正確的)值可以使用Applicative和Functor進行組合和修改,而Left over bad值會頑固地持續存在,所以這對於像簡單的編譯器可能報告第一個錯誤那樣是很好的。 – AndrewC

回答

10

這是因爲在Functor實例(和Applicative等)的類型參數是所述第二類型參數。在

Either a b 

a類型和Left值不受函子或應用性的操作,因爲它們被認爲是失敗的案例或以其他方式不可訪問。

instance Functor (Either a) where 
    fmap _ (Left x) = Left x 
    fmap f (Right y) = Right (f y) 

使用Right

(++) <$> Right "Hello" <*> Right " World" 

得到串聯。

+0

如果您想要翻轉類型變量,可以使用'errors'包中的'Data.EitherR'模塊。這提供了兩個選項:'flipE',它翻轉一個參數'Either'或'EitherR',它將它換成一個新類型,交換變量順序,給出對稱的'Functor'和'Applicative'實例。 –

6

要添加到丹尼爾的出色答卷,有幾個點我想提出:

首先,here's應用型實例:

instance Applicative (Either e) where 
    pure    = Right 
    Left e <*> _ = Left e 
    Right f <*> r = fmap f r 

你可以看到,這是「短期短路「 - 只要它遇到Left,它會中止並返回該左側。你可以檢查這與窮人的嚴格性分析:

ghci> (++) <$> Left "Hello" <*> undefined 
Left "Hello"        -- <<== it's not undefined :) !! 

ghci> (++) <$> Right "Hello" <*> undefined 
*** Exception: Prelude.undefined   -- <<== undefined ... :(

ghci> Left "oops" <*> undefined <*> undefined 
Left "oops"        -- <<== :) 

ghci> Right (++) <*> undefined <*> undefined 
*** Exception: Prelude.undefined   -- <<== :( 

其次,你的例子有點棘手。通常,函數的類型與Either e中的e不相關。這裏的<*> S型:

(<*>) :: Applicative f => f (a -> b) -> f a -> f b 

如果我們做替代f - >>Either e,我們得到:

(<*>) :: Either e (a -> b) -> Either e a -> Either e b 

儘管在你的榜樣,ea匹配,一般他們不會,這意味着您不能多態地實現Either e的應用實例,該實例將函數應用於左側參數。

相關問題