Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: function composition resulted in type-mismatch error

Tags:

haskell

ghci

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?

like image 551
iceman Avatar asked Jan 01 '26 14:01

iceman


1 Answers

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

like image 124
yatima2975 Avatar answered Jan 03 '26 12:01

yatima2975



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!