简体   繁体   中英

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?

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM