Попытка понять оператор приложения приложения в Haskell

Я пытаюсь обернуть голову вокруг оператора приложения функции ($) в Haskell.

Я работаю над примерами в "Learn You a Haskell", и я подумал, что понял следующий пример:

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

Затем я попробовал следующий вариант, который также отлично работал:

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

Наконец, я попытался изменить третью функцию в списке следующим образом, которая генерирует ошибку:

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> 

Кажется, что конечная функция sqrt как-то начинает ассоциироваться с предыдущим элементом списка, так как следующий вариант работает нормально:

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

Может кто-нибудь просветить меня о том, что происходит здесь?

Ответ 1

Тип используемого оператора возведения в степень

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

поэтому, когда вы используете \x -> 2^x, вы получаете ограничение Integral для 3. Но sqrt накладывает ограничение Floating. Таким образом, тип 3 должен удовлетворять

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

но нет экземпляра для списка типов по умолчанию, который равен Integer и Double, поэтому по умолчанию происходит сбой, и вы остаетесь с неоднозначной переменной типа.

Когда у вас было \x -> x^2, из первых функций было только ограничение Num и Floating из sqrt, поэтому по умолчанию тип был Double.

Вы можете заставить его работать, если вы используете

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

как ваш оператор экспоненции, тогда тип снова может быть по умолчанию Double.