3
votes

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):

enter image description here

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?

1
Do you have MonomorphismRestriction turned on? What are the types of b and foldingFunc? (Inspect the types with :t in ghci.)Rufflewind
bingo, just turned it off and it's working correctly now. thanks a lot. if you copy paste your comment into an answer, i will (happily!) accepticeman
yatima2975 beat me to it. :)Rufflewind
@Rufflewind: Sorry, I didn't see your comment while typing my explanation :-)yatima2975
@yatima2975 Nah it's fine. You went into a lot more detail than I would've!Rufflewind

1 Answers

8
votes

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:

  1. Add an argument to 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.
  2. Switch off the monomorphism restriction, either by adding a {-# LANGUAGE NoMonomorphismRestriction #-} pragma at the top of your file, or doing it interactively by entering :set -XNoMonomorphismRestriction at ghci's command line.
  3. Upgrade to a newer version of GHC (7.8.3 does the trick for me).

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 :)