Reputation: 17051
This question arose while reading the new chapter in the excellent Learn You a Haskell about applicative functors.
The Applicative typeclass has, as part of the definition for the Maybe instance:
pure = Just
If I just go to GHCi and import Control.Applicative, and do:
pure (3+)
I don't get Just anything (makes sense). But if I use it in part of the expression:
pure (3+) <*> Just 4
I get Just 7. I guess it also isn't surprising, but I'm missing something integral about how typeclasses work, I think, that there is no ambiguity with the call to pure
here.
If my confusion makes sense, can anyone explain what's going on in detail?
Upvotes: 4
Views: 806
Reputation: 45117
Here is an interesting SO thread on type inference. Not Haskell specific, but lots of good links and stuff to read about type inference in functional languages.
Upvotes: 1
Reputation: 202465
It's worth looking at the type the compiler infers for pure (3+)
:
Prelude Control.Applicative> :t pure (3+)
pure (3+) :: (Num a, Applicative f) => f (a -> a)
The type of this term is overloaded, and the decision about the numeric class and the applicative class is delayed until later. But you can force a particular type with an annotation, for example:
*Showfun Control.Applicative> pure (3+) :: Maybe (Double -> Double)
Just <function>
(This works because Showfun
has an instance declaration that prints a function value as <function>
.)
It's just a question of when the compiler has accumulated enough information to make a decision.
Upvotes: 3
Reputation: 231063
To expand a bit on newacct's answer, if there isn't enough information to infer the actual type, the compiler may (in some cases) attempt to select a default type, limited to those that would satisfy the type constraints in question. In this case, the type inferred is IO (n -> n) for some difficult-to-determine instance of Num => n. GHCi then evaluates it and throws away the return value, with no visible effect.
Upvotes: 2
Reputation: 122419
It's just type inference. The (<*>)
operator requires both arguments to use the same Applicative
instance. The right side is a Maybe
, so the left side has to be a Maybe
also. So that's how it figures out which instance is used here. You can look at the type of any expression in the interpreter by typing :t expression
, and maybe if you just go through each subexpression and look at the type that was inferred, you will get a better picture of what's going on.
Upvotes: 7