Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to understand function application operator in Haskell

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?

like image 708
Paul M. Avatar asked Mar 12 '13 13:03

Paul M.


1 Answers

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.

like image 70
Daniel Fischer Avatar answered Oct 12 '22 01:10

Daniel Fischer