views:

307

answers:

4

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?

+5  A: 

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.

newacct
Ah, so does the compiler do something like "Hmm, this argument's type is ambiguous, so let me check the next argument's type and come back to it"?
J Cooper
Type inference is quite complex, but it's worth knowing that it doesn't happen in one step. The type inferencer usually collects some information in one step, and at a later stage some more information. So it doesn't just infer the correct types for everything in one go, from left to right. In this case, it will infer that `pure` is of type `(Applicative a1) => a1 (Int -> Int)` where the `a1` is just a made up type variable, at a later stage during type inference it will conclude that `a1` must be `Maybe`, and then it will substitute `Maybe` for `a1` everywhere.
Tom Lokhorst
Thank you -- that is quite helpful!
J Cooper
+2  A: 

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.

bdonlan
+3  A: 

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.

Norman Ramsey
Out of curiosity, is the `Showfun` module in some existing package, or is is just something you wrote yourself? The implementation is straightforward enough: `instance Show (a -> b) where; show _ = "<function>"`
Tom Lokhorst
I wrote Showfun myself so I could get the example `pure (3+)` to print using `Just`.
Norman Ramsey
ShowFunctions is in QuickCheck now, I believe.
Porges
+1  A: 

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.

JP Alioto