5
votes

I'm using GHCi (version 6.12.3) to play a bit with Haskell. I recently read about functors and applicative functors thought if you couldn't something similar to <*> of applicative functors be implemented only using functor's primitives. After some thinking I came up with fmap fmap which would have a (nearly) ideal type of

Functor f => f (a -> b) -> f (f a -> f b) or more generically

(Functor f1, Functor f2) => f1 (a -> b) -> f1 (f2 a -> f2 b)

I tried

let q = fmap fmap

I got the following error

<interactive>:1:8:
    Ambiguous type variable `f1' in the constraint:
      `Functor f1' arising from a use of `fmap' at <interactive>:1:8-16
    Probable fix: add a type signature that fixes these type variable(s)

<interactive>:1:13:
    Ambiguous type variable `f' in the constraint:
      `Functor f' arising from a use of `fmap' at <interactive>:1:13-16
    Probable fix: add a type signature that fixes these type variable(s)

Writing the above type signature as suggested didn't help. The craziest thing is when i typed :t fmap fmap I got an equivalent type as the above.

What am I doing wrong? Why does fmap fmap give a type error although GHCi finds a type for it?

2

2 Answers

7
votes

Looks like you're running into the monomorphism restriction.

Trying your example in GHCi with -XNoMonomorphismRestriction gives your expected result.

You can also subvert this by writing let f x = fmap fmap $ x. The monomorphism restriction only applies to top-level definitions which "look like" values, i.e. f = something, so introducing an explicit argument causes it not to apply anymore. It would also not apply if this was not at the top level (for example in a where clause). For more details, see the link.

1
votes

I can't comment everywhere yet so I'll post an answer. As mentioned earlier the error you're receiving is due to the monomorphism restriction. Fixing the type signature to either of the two given in the original question does indeed make ghci happy like you were hoping, maybe you just got the syntax slightly wrong?

Prelude> let q :: (Functor f) => f (a -> b) -> f (f a -> f b); q = fmap fmap
Prelude> :t q
q :: (Functor f) => f (a -> b) -> f (f a -> f b)

Prelude> let q :: (Functor f1, Functor f2) => f1 (a -> b) -> f1 (f2 a -> f2 b); q = fmap fmap
Prelude> :t q
q :: (Functor f1, Functor f2) => f1 (a -> b) -> f1 (f2 a -> f2 b)