Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non type-variable argument in the constraint error on Haskell map function

Tags:

haskell

I am writing a function called mapper2 that applies a function to two lists:

mapper2 :: (a-> b -> c) -> [a] -> [b] -> [c]
mapper2 f (x:xs) (y:ys) = (f x y) : (mapper2 f xs ys)
mapper2 _ _ _ = []

I am able to compile the function but get an error when I apply it:

*Main> mapper2 (\x -> x*2) [2,4] [4,6] 

<interactive>:4:1: error:
    • Non type-variable argument in the constraint: Num (b -> c)
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        it :: forall b c. (Num (b -> c), Num b) => [c]

Can someone explain to me how to fix this and what the error means?

like image 354
Gloriane Avatar asked Nov 30 '16 17:11

Gloriane


2 Answers

Look at mapper2's type.

mapper2 :: (a -> b -> c) -> [a] -> [b] -> [c]

Now look at the type of the function you're passing in.

(\x -> x * 2) :: Num a => a -> a

The mapper2 function expects a function of two arguments to be passed in, but your lambda only takes one argument.

like image 44
Silvio Mayolo Avatar answered Sep 17 '22 19:09

Silvio Mayolo


Silvio Mayolo has covered the main, practical part of the question, so I will stick to the technical details related to...

what the error means?

To begin with, the error is a bit hairy, but one thing that you can focus on at first is the Num (b -> c) bit. It indicates that you are somehow trying to use a function type (b -> c) as a number (i.e. an instance of Num), which is something that is almost never done intentionally (as we usually do not use functions as numbers). More often than not, when such things happen it is a sign that there is a mismatch in the number of arguments somewhere (which is the case here, as explained by Silvio Mayolo's answer). That said, what follows is an explanation of how the error comes about.

The first argument of mapper2 has type a -> b -> c or, equivalently, a -> (b -> c). When you pass...

(\x -> x * 2) :: Num z => z -> z

... to it, a -> (b -> c) and Num z => z -> z are matched (or, using the jargon, unified), so that the first z becomes a and the second z becomes b -> c. Since both z are supposed to be the same thing, a becomes b -> c as well, and so the type of (\x -> x * 2) is specialised to:

(\x -> x * 2) :: Num (b -> c) => (b -> c) -> (b -> c)

The error message Non type-variable argument in the constraint: Num (b -> c) refers to how, unlike in e.g. Num x, there is something within the constraint that is not a type variable. In this case, it is function type constructor, ->. While turning on the FlexibleContexts extension, as the error message suggests, would allow that, there is no reason to do so here, as it still wouldn't be what you want (you have no intention of using functions as numbers). Furthermore, doing so in this case would just lead to another type error.

like image 163
duplode Avatar answered Sep 18 '22 19:09

duplode