Reputation: 2130
TL;DR: What can cause a type-mismatch error in GHCi purely as a result of function composition? It's odd to see GHCi evaluate the following code:
foldl (a . b . c) crackle pop <- GHCi evaluates this`
...only to give an error after we try to evaluate the following:
let snap = a . b . c <- GHCi evaluates this
foldl snap crackle pop <- GHCi reports an error (!)
The longer version:
I am baffled by what I'm observing here in GHCi and am hoping someone can explain it (description included below image):
What do we see above?:
First, we have a variable b
which is bound to the following list: [(2,["Dipak"]), (2,["Andrew"]),(2,["Keone"])]
. b
is of type [(Int,[String])]
. (See the first ghci>
prompt and the resulting output in the screenshot above.)
We then perform a fold on b
, transforming it into the following type: Map (Integer, [String])
. We do so by using a folding function based on insertWith (++)
a starting accumulator that is an empty
map. The function is as follows (same as what follows the second ghci>
prompt in the screenshot above. (See second ghci>
prompt above.)
foldl' (flip $ uncurry (Map.insertWith (++))) (Map.fromList []) b
Okay, cool; so far, so good
Given the foldl'
function above was a mouthful, I decided to compose a folding function (named foldingFunc
) which was equal to flip $ uncurry (Map.insertWith (++))
. This is simply the first argument of foldl'
in the expression above. (See let
expression in the third ghci>
prompt above.)
This is where I get confused: as a routine check, I perform the same foldl'
as above, except with foldingFunc
(in lieu flip $ uncurry (Map.insertWith (++))
) which should simply be a cosmetic change...and now GHCi reports a type mismatch error (details above).
Can someone please help me understand why function composition led to an error (as a result of a type change) in this case? And what should I be doing differently?
Upvotes: 3
Views: 298
Reputation: 6610
The dynamic duo of ghci's extended defaulting rules and the Dreaded Monomorphism Restriction strike again!
I'm guessing you're using a slightly out-of-date ghci, version 7.6 or earlier.
What happens is that foldingFunction
has as most general type
foldingFunction :: Ord a => Map a [b] -> (a,[b]) -> Map a [b]
However, since it's a top-level definition without arguments and your version of ghci still has the monomorphism restriction, this isn't a 'good' type (it's polymorphic because of the context Ord a
), and the defaulting rules kick in. ghci tries to find a default instance for Ord a
- normally this would fail (since there is no Num
-like constraint), but ghci also considers ()
as a possible default. That works, so if you ask ghci for the type of foldingFunction
you'll get
foldingFunction :: Map () [b] -> ((), []) -> Map () []
which is where your type error comes from. (I hope I've guessed correctly!)
There are a couple of ways around this:
foldingFunction
: if you use foldingFunction m = (flip $ uncurry (Map.insertWith (++))) m
or maybe nicer foldingFunction m (a,bs) = insertWith (++) a bs m
it'll start working.{-# LANGUAGE NoMonomorphismRestriction #-}
pragma at the top of your file, or doing it interactively by entering :set -XNoMonomorphismRestriction
at ghci's command line.Both having the DMR off by default and the extended defaulting rules are fairly recent (last couple of years) additions to ghci, so it might even be that the book or text you're using are too old :)
Upvotes: 8