문제

I have been working through the great good book, but I am struggling slightly with Applicative Functors.

In the following example max is applied to the contents of the two Maybe functors and returns Just 6.

max <$> Just 3 <*> Just 6

Why in the following example is Left "Hello" returned instead of the contents of the Either functors: Left "Hello World"?

(++) <$> Left "Hello" <*> Left " World"
도움이 되었습니까?

해결책

It's because the type parameter in the Functor instance (and Applicative etc.) is the second type parameter. In

Either a b

the a type, and the Left values are not affected by functorial or applicative operations, because they are considered failure cases or otherwise inaccessible.

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

Use Right,

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

to get concatenation.

다른 팁

To add to Daniel's excellent answer, there are a couple points I'd like to make:

First, here's the Applicative instance:

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

You can see that this is 'short-circuiting' -- as soon as it hits a Left, it aborts and returns that Left. You can check this with poor man's strictness analysis:

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          -- <<== :( 

Second, your example is slightly tricky. In general, the type of the function and the e in Either e are not related. Here's <*>s type:

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

If we make the substitution f -->> Either e, we get:

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

Although in your example, e and a match, in general they won't, which means you can't polymorphically implement an Applicative instance for Either e which applies the function to a left-hand argument.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top