I think there is a type mismatch in default definition in instance Applicative Maybe in Haskell
Clash Royale CLAN TAG#URR8PPP
I think there is a type mismatch in default definition in instance Applicative Maybe in Haskell
I am currently studying Haskell with Prof. Hutton's "Programming in Haskell", and I found something strange regarding the definition of Maybe as an instance of the class Applicative.
In GHC.Base
, the instance Applicative Maybe
is defined as follows:
GHC.Base
Applicative Maybe
instance Applicative Maybe where
pure = Just
Just f <*> m = fmap f m
Nothing <*> _m = Nothing
It is the line which defines the value of Nothing <*> _
as Nothing
that bothers me. Nothing
is of type Maybe a
, where the operator <*>
actually requires f (a -> b)
(in this case, Maybe (a -> b)
) as its first argument's type. Therefore, this is a type mismatch, which Haskell should complain about. However, this is accepted as a default definition, and therefore Haskell does not complain about it where I think it should.
Nothing <*> _
Nothing
Nothing
Maybe a
<*>
f (a -> b)
Maybe (a -> b)
What am I missing?
2 Answers
2
The a
in Maybe a
is a type variable, and can be any type at all! So Nothing
can have the type Maybe Int
, or Maybe [x]
, or Maybe (p -> q)
, for example.
Don't get confused by the fact that the variable name a
is used in two places. The a
in the type of Nothing
is a completely different variable from the a
in the type of <*>
, and just happens to have the same name!
a
Maybe a
Nothing
Maybe Int
Maybe [x]
Maybe (p -> q)
a
a
Nothing
a
<*>
(That's exactly the same as if you wrote f x = x + 5
and then elsewhere, g x = "Hello, " ++ x
. The use of x
in both places doesn't matter, because they are in different scopes. Same with the a
in this types. Different scopes, so they are different variables.)
f x = x + 5
g x = "Hello, " ++ x
x
a
Let's make things clearer by relabeling a type variable:
Nothing :: Maybe x
The type Maybe x
unifies with Maybe (a -> b)
, with x ~ (a -> b)
. That is, Nothing
is a value that can used as Maybe a
for any a
, including a function type. Thus it is a legal left-hand argument for <*>
here.
Maybe x
Maybe (a -> b)
x ~ (a -> b)
Nothing
Maybe a
a
<*>
Thank you for your answer. Small follow-up question here: should I read x ~ (a -> b) as "the variable x is associated with type (a -> b)"?
– Namudon'tdie
Aug 13 at 4:15
@Namudon'tdie:
x ~ y
is a type equality constraint. Informally, people use it to mean “the type x
is equal to the type y
”; in Haskell, you can use this syntax as a typeclass constraint when certain extensions are enabled (e.g. GADTs
or TypeFamilies
). It’s mainly useful for controlling typeclass instance resolution and aiding type-level programming.– Jon Purdy
Aug 13 at 6:04
x ~ y
x
y
GADTs
TypeFamilies
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Oh, I get it! So, 'a' in "Maybe a" is a very broad generalization of any type that can be given to the constructor function "Maybe". Thanks a lot!
– Namudon'tdie
Aug 13 at 4:13