要添加到丹尼爾的出色答卷,有幾個點我想提出:
首先,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
儘管在你的榜樣,e
和a
匹配,一般他們不會,這意味着您不能多態地實現Either e
的應用實例,該實例將函數應用於左側參數。
這是傳統用法,無論是Right表示您感興趣的值,而Left表示失敗。正確的(正確的)值可以使用Applicative和Functor進行組合和修改,而Left over bad值會頑固地持續存在,所以這對於像簡單的編譯器可能報告第一個錯誤那樣是很好的。 – AndrewC