2012-12-14 10 views
5

私はgreat goodの本を使っていますが、私はApplicative Functorsとやや苦労しています。Applicative FunctorsとLeft from Either

次の例では、maxが2つのMaybeファンクタの内容に適用され、Just 6を返します。

max <$> Just 3 <*> Just 6 

次の例ではLeft "Hello"はどちらかファンクタの内容の代わりに返される理由:Left "Hello World"

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

これは伝統的な使い方です。右は興味のある値を表し、左は失敗を表します。 ApplicativeとFunctorを使用して右(正しい)値を結合したり変更することができますが、残った値を残しておくと頑丈に保持されるため、単純なコンパイラの場合と同様に最初のエラーを報告するのに適しています。 – AndrewC

答えて

10

Functorインスタンス(およびApplicative等)を入力パラメータが第二型パラメータであるためにです。

Either a b 

aタイプ、およびそれらが障害事例とみなさまたはそうでなければアクセスできないされているのでLeft値は、functorial又は応用的操作によって影響されません。

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

使用Right

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

連結を取得します。

まず、here's Applicativeのインスタンス:ダニエルの優れた答えに追加するには

+0

タイプ変数を反転したい場合は、 'errors'パッケージの' Data.EitherR'モジュールを使用することができます。これは二つのオプションを提供します: 'flipE'は可変の順序を入れ替えるnewtypeでそれを包む引数' Either'または 'EitherR'を反転し、対称' Functor'と 'Applicative'インスタンスを与えます。 –

6

、私がしたいのですがカップルのポイントがあります

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

あなたは、これは「短期であることがわかります回路化 ' - Leftに達するとすぐに、それは中止され、その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   -- <<== :( 

次に、あなたの例は若干トリッキーです。一般的には、関数の型とeEither eには関係ありません。ここで<*>の型です:私たちが行った場合

(<*>) :: 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のApplicativeインスタンスをポリモーフィックに実装することはできません。このインスタンスは、左の引数に関数を適用します。