10

I'm trying to wrap my head around the function application operator ($) in Haskell.

I'm working through the examples in Learn You a Haskell, and I thought I understood the following example:

Prelude> map ($ 3) [(+4), (*10), (^2), sqrt]
[7.0,30.0,9.0,1.7320508075688772] 

I then tried the following variant, which also worked fine:

Prelude> map ($ 3) [(+4), (*10), (\x -> x^2), sqrt]
[7.0,30.0,9.0,1.7320508075688772]

Finally, I tried modifying the third function in the list as follows, which generates an error:

Prelude> map ($ 3) [(+4), (*10), (\x -> 2^x), sqrt] 
<interactive>:53:38:
    Ambiguous type variable `b0' in the constraints:
      (Floating b0)
        arising from a use of `sqrt' at <interactive>:53:38-41
      (Integral b0) arising from a use of `^' at <interactive>:53:33
      (Num b0) arising from the literal `3' at <interactive>:53:8
    Probable fix: add a type signature that fixes these type variable(s)
    In the expression: sqrt
    In the second argument of `map', namely
      `[(+ 4), (* 10), (\ x -> 2 ^ x), sqrt]'
    In the expression: map ($ 3) [(+ 4), (* 10), (\ x -> 2 ^ x), sqrt]
Prelude> 

It seems if the final sqrt function is somehow begin associated with the previous list element, as the following variant works ok:

Prelude> map ($ 3) [(+4), (*10), (\x -> 2^x)]
[7,30,8]

Can someone enlighten me as to what's going on here?

1
  • one lesson to take from this, after trying something out at GHCi prompt, check its type, with Prelude> :t it. "It" is a special word, referring to the previous result, and :t asks to see a type. You could see that there are no decimal points in the numbers in your last example. Also, after entering :s +t at the prompt, the GHCi will report the type for every result it produces. Commented Mar 13, 2013 at 9:06

1 Answer 1

17

The type of the used exponentiation operator is

(^) :: (Num a, Integral b) => a -> b -> a

so when you use \x -> 2^x, you get an Integral constraint for the 3. But sqrt imposes a Floating constraint. So the type of the 3 must satisfy

3 :: (Integral t, Floating t) => t

but there is no instance for both among the default type list, which is Integer and Double, so the defaulting fails, and you're left with an ambiguous type variable.

When you had \x -> x^2, there was only a Num constraint from the first functions, and Floating from sqrt, so the type was defaulted to Double.

You can make it work if you use

(**) :: Floating a => a -> a -> a

as your exponentiation operator, then the type can again be defaulted to Double.

Sign up to request clarification or add additional context in comments.

2 Comments

Then he could fix it, replacing (^) by (**).
Thanks both Daniel and Zurgl -- that clarifies things considerably. Coming from Python I'm still wrapping my head around the implications of strict type checking.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.