Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top