Как карри функции в Haskell

У меня есть функция multThree для умножения 3 чисел, которая работает с карри. Однако, когда я попытался расширить это на умножение четырех чисел, используя ту же структуру, это не сработало. Почему это и как это можно исправить?

multThree :: Num a => a -> (a -> (a -> a))
multThree x = (*) . (*) x

multFour :: Num a => a -> (a -> (a -> (a -> a)))
multFour x = (*) . (*) . (*) x

Ошибка дана:

• Occurs check: cannot construct the infinite type: a ~ a -> a
  Expected type: a -> a -> a -> a
    Actual type: a -> (a -> a) -> a -> a
• In the expression: (*) . (*) . (*) x
  In an equation for ‘multFour’: multFour x = (*) . (*) . (*) x
• Relevant bindings include
    x :: a (bound at test2.hs:19:10)
    multFour :: a -> a -> a -> a -> a

1 ответ

Решение

Давайте выпишем это без (.):

multFour x = (*) . (*) . (*) x
= (*) . (\y -> (y*)) . (x*)
= (\w -> (w*)) . (\z -> ((x*z)*))
= (\w -> (w*)) . (\z v -> x*z*v)
= \z -> \u -> (\v -> x*z*v) * u

Итак, мы видим, что мы пытаемся умножить функцию на число.

Ключевая ошибка заключается в следующем:

multFour x = (*) . multThree x

И типы:

(*) :: Num a => a -> (a -> a)
multThree x :: Num b => b -> (b -> b)
x :: b
(.) :: (y -> z) -> (x -> y) -> (x -> z)

Таким образом, типы объединяются как:

a = y
z = (a -> a)
b = x
y = b -> b
multFour :: Num b => b -> x -> z
multFour :: (Num b, Num (b -> b)) => b -> b -> (b -> b) -> (b -> b)

Который не тот тип, который вы хотите.

Чтобы исправить ваш код, я рекомендую:

multFour a b c d = a * b * c * d

Это гораздо более читабельно.

Другие вопросы по тегам