Reputation: 355
I was just trying out some simple Haskell codes after learning Applicative and Monad, and was confused by the application of pure
and <$>
. I do understand the definitions, but in some special cases they seem to be mix up a little bit.
Say, I wish to get a function foo
, which takes a Maybe Int
and a Maybe [Int]
, and concat the first argument to the second one. A typical definition could be:
foo :: Maybe Int -> Maybe [Int] -> Maybe [Int]
foo ma mb = (:) <$> ma <*> mb
so that foo (Just 1) (Just [2])
would give Just [1,2]
.
But it seems pure
makes no sense in this case, no matter how hard I tried to make the (:)
an applicative one. Furthermore, pure (:) (Just 1)
works in the exactly same manner as (:)
does, but how could it be? I suppose (:)
takes two arguments, so the previous one should be an applicative curried function?
Thank you so much!
Upvotes: 2
Views: 149
Reputation: 116139
Furthermore,
pure (:) (Just 1)
works in the exactly same manner as(:)
does, but how could it be?
Because of polymorphism and instance resolution. We have that
pure (:) :: Applicative f => f (a -> [a] -> [a])
Note how this works for any applicative f
, not only for Maybe
.
Then we apply it to (Just 1)
which (after defaulting) has type, say, Maybe Int
. So, to type check everything we need
pure (:) :: Maybe Int -> result
for some result
type. We can write the above as
pure (:) :: (->) (Maybe Int) result
We then try to infer what f
is, searching for a solution of
f (a -> [a] -> [a]) ~ (->) (Maybe Int) result
ergo,
f ~ (->) (Maybe Int)
(a -> [a] -> [a]) ~ result
Since (->) (Maybe Int)
is an applicative, we accept this f
. We then get
pure (:) (Just 1) :: a -> [a] -> [a] -- AKA result
Now, what is pure
in the (->) (Maybe Int)
applicative?
instance Applicative ((->) b) where
pure x = \_ -> x
-- ...
So, pure
simply discards the second Just 1
argument and returns the first one (:)
.
Concluding: the issue is that pure (:)
does not have to work on the applicative you had in mind, Maybe
, but is more general and will search for any applicative that makes the code to type check. If you apply pure (:)
to something, the (->) b
instance gets selected, and the second argument discarded.
There is a big difference from pure f y
(which is equivalent to f
) and pure f <*> y
(which is equivalent to f <$> y
).
Upvotes: 8