Ваше базовое понимание того, что выделка это правильно. В частности, речь идет о преобразовании функции, которая принимает аргументы как кортеж, такие как, например
add :: (Int, Int) -> Int
add (x, y) = x + y
в функцию, которая принимает его аргументы по одному:
add' :: Int -> Int -> Int
add' x y = x + y
Эта схема позволяет для того, чтобы подвергнуть теперь текущую функцию частичным приложением, то есть применять ее с некоторыми, но не всеми ее аргументами. Например, мы можем иметь
succ :: Int -> Int
succ = add' 1
где мы применяем add'
первого аргумента и дают функцию, которая по-прежнему ожидает, что оставшиеся аргументы.
Обратное преобразование называется неуправляемым и превращает функцию, которая принимает аргументы «один за другим» в функцию, которая принимает свои аргументы «все сразу» как кортеж.
Оба преобразования могут быть захвачены семействами функций более высокого порядка. То есть, для бинарных функций есть
curry :: ((a, b) -> c) -> (a -> b -> c)
curry f = \x y -> f (x, y)
uncurry :: (a -> b -> c) -> ((a, b) -> c)
uncurry f = \(x, y) -> f x y
Для троичных функций есть
curry3 :: ((a, b, c) -> d) -> (a -> b -> c -> d)
curry3 f = \x y z -> f (x, y, z)
uncurry3 :: (a -> b -> c -> d) -> ((a, b, c) -> d)
uncurry3 f = \(x, y, z) -> f x y z
И так далее.
Теперь давайте посмотрим на ваш пример:
2 * (\x y -> x * y) 2 3
Здесь вы умножая буквального 2
с результатом применения функции (\x y -> x * y)
, который умножает два своих аргумента x
и y
. Как вы можете видеть, эта функция уже принимает свои аргументы «один за другим». Следовательно, она уже налита.Итак, что подразумевается в вашем учебнике, если они просят написать карри-версию этого выражения вне меня. Мы могли бы написать uncurried, указав, что функция умножения принимает аргументы «все одновременно»: (\(x, y) -> x * y)
. Тогда мы получим
2 * (\(x, y) -> x * y) (2, 3)
Теперь заметим, что можно написать (\(x, y) -> x * y)
как uncurry (*)
, который дал бы нам
2 * uncurry (*) (2, 3)
Если мы uncurry первое приложение (или на самом деле приложения, множественное число ;-)) из (*)
, получим
uncurry (*) (2, uncurry (*) (2, 3))
Я сомневаюсь, было ли намерение за упражнение в вашем учебнике, но я надеюсь, что это дает вам сом проницательность в карри и неумело.
Начните с ответа на более простой вопрос: что такое тип '(\ x y -> x * y)'? –
Int -> Int -> Int? или Num a => a -> a -> a – Steve
Последнее. Но первый тоже сделает для этой цели. –