2013-04-15 3 views
1

Я изучаю Haskell и пытаюсь понять, как применить концепцию currying к функциям. Я понимаю, что каррирование - это, по сути, средство для использования функции с несколькими аргументами и применения функции к одному аргументу, возвращая функцию, применяемую ко второй, и т. Д. ... без потери выразительности. Один учебника я работаю спрашивает:Напишите «карри-версию» выражения лямбда

«Написать каррированную версию 2 * (\x y -> x*y)2 3»

Я надеюсь, что кто-то может помочь мне показать, как решить эту проблему. Заранее спасибо

Edit: В ответ на два комментаторов, я могу видеть, что признание

(\x y -> x*y) :: Num a => a -> a -> a

... это мой первый шаг. У меня довольно медленная кривая обучения, когда дело доходит до функционального программирования (а также новый плакат SO, чтобы оправдать любой этикет, который я сломал) ... каким будет мой следующий шаг?

Edit 2: @Mikhail, я вижу, что uncurry применяется к типу лямбда-выражения будет что-то вида (учитывая uncurry :: (a -> b -> c) -> (a,b) -> c)

Num a => (a,a) -> a 
+0

Начните с ответа на более простой вопрос: что такое тип '(\ x y -> x * y)'? –

+0

Int -> Int -> Int? или Num a => a -> a -> a – Steve

+0

Последнее. Но первый тоже сделает для этой цели. –

ответ

5

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

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)) 

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

+0

Спасибо за ответ. Это, безусловно, помогло мне понять концепцию немного лучше. – Steve

+0

Вероятно, стоит отметить, предыдущий вопрос выглядит следующим образом: 3) Написать 'F :: Int -> Int -> Int FXY = 2 * х + у е 2 3' с помощью лямбда-выражения 4) Напишите нарисованную версию этого выражения лямбда ... Выражение, которое вы видите выше, является моим ответом на 3), таким образом, я подозреваю, что это вопрос, который задает вопрос – Steve

+0

@Steve: Возможно, он хотел, чтобы вы его явно выписали как множественные одиночные аргументы лямбда? например, '(\ x -> (\ y -> ...))'. Это ... бессмысленно, и использование термина «curried» неверно, но я полагаю, он подчеркивает, что форма '(\ x y -> ...)' эквивалентна (стенография, действительно). –