In the source code of GHC.Base, Applicative Maybe is defined as:
instance Applicative Maybe where
pure = Just
...
I am wondering why the pure's definition ignores Nothing?
According to this definition, I am expecting that
pure Nothing should reduce to Just Nothing because pure = Just and
Prelude> Just Nothing
Just Nothing
rather than actually:
Prelude> pure Nothing
Nothing
Why is this magic? What is my wrong? Thanks!
It does not ignore Nothing, but you need to specify for which Applicative you run the pure function, if we run this with -XTypeApplications, we can specify the type of the Applicative, and then we obtain:
$ ghci -XTypeApplications
GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help
Prelude> pure @Maybe Nothing
Just Nothing
If you do not specify the type, the interpreter will "default" to a certain Applicative (in this case the the IO) variant, so that means that it will return the value, and the standard behavior of the interpreter is to print the value "wrapped" in the IO shell.
The reason why Applicative takes pure = Just, is because it has to be consistent with the Functor instance. This functor instance is defined as:
instance Functor Maybe where fmap f (Just x) = Just (f x) fmap _ Nothing = Nothing
Now one of the laws that needs to be satisfied is:
fmap f x = pure f <*> x
So if we would define pure _ = Nothing, then this would mean fmap f x = Nothing <*> x which means that we "lost information" about f. As a result probably the only reasonable solution would be that fmap always returns Nothing, but that would not make much sense as a functor. It will furthermore violate another constraint at the functor level that says that fmap id x should always return x.
pure is overloaded. When you just type pure Nothing on its own, you don’t specify which version of pure to call. On its own, it actually has type
pure Nothing :: Applicative f => f (Maybe a)
If you specifically say you want Maybe (Maybe a), you’ll get what you expect:
ghci> pure Nothing :: Maybe (Maybe a)
Just Nothing
When you type pure Nothing into GHCi, though, it actually chooses to make a IO (Maybe a). This is because GHCi tries to run any IO action it can. When it executes the action pure Nothing :: IO (Maybe a), then you get back Nothing. You can also give a type signature:
ghci> pure Nothing :: IO (Maybe a)
Nothing
That is, you never called the pure = Just version of pure. You called a different function, also named pure. This is why you got some interesting behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With