Новичок: каррированные функции в схеме

Я использую лекции и текст SICP, чтобы узнать о Scheme самостоятельно. Я смотрю на упражнение, в котором говорится: «Применение выражения E является выражением формы (E E1,... En). Это включает случай n = 0, соответствующий выражению (E). Карри-приложение of E является либо приложением E, либо приложением Curried приложения E».

(Правка: я исправил приведенную выше цитату... Изначально я неверно процитировал определение.)

Задача состоит в том, чтобы определить Curried-приложение процедуры, которое вычисляет значение 3 для

(define foo1
    (lambda (x)
        (* x x)))

Я действительно не понимаю эту идею, и чтение статьи в Википедии о Curriying не очень помогло.

Может ли кто-нибудь помочь с более ясным объяснением того, о чем здесь просят?

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

Дополнение: даже после длинных объяснений Брайана Кэмпбелла я все еще несколько потерян.

Является ли (foo1 (sqrt 3))) приложением foo и, следовательно, каррированным приложением foo?

Кажется слишком простым, но может быть...

Ввод (((foo1 2 )) 2) в DrScheme дает следующую ошибку (чего я и ожидал)

procedure application: expected procedure, given: 4 (no arguments)

После повторного чтения Что такое каррирование? я понимаю, что также могу переопределить foo1 так:

(define (foo1 a)
    (lambda (b)
        (* a b)))

Тогда я могу напечатать

((foo1 3 ) 4)

12

Но на самом деле это не приближает меня к созданию 3 в качестве вывода, и кажется, что на самом деле это не каррирование исходного foo1, а просто его переопределение.

Блин, 20 лет программирования на C не подготовили меня к этому. :-) :-)


person Leonard    schedule 29.03.2009    source источник
comment
У вас несбалансированная двойная кавычка. Где заканчивается ваша цитата?   -  person Svante    schedule 29.03.2009
comment
Я обновил свой ответ некоторыми разъяснениями и ответами на ваши правки. Старайтесь не думать о других определениях каррирования, которые вы видите; в этом упражнении речь идет не об определении функции Curried, а о применении функции Curried.   -  person Brian Campbell    schedule 29.03.2009
comment
Пожалуйста, дайте мне знать, помог ли мой отредактированный ответ! Поскольку вы пытаетесь этому научиться, я пытаюсь дать вам достаточно информации, чтобы вы могли решить проблему, не решая ее самостоятельно; если вы хотите, чтобы я вообще расширил свое объяснение, я, безусловно, готов.   -  person Brian Campbell    schedule 30.03.2009
comment
@Brian: Ваш ответ определенно помог. Спасибо, что подбодрили меня. Я решил вернуться и перечитать более ранние части книги, вплоть до версии 1.3, как вы предложили, и это побочный проект, а не полный рабочий день, поэтому работа идет медленно.   -  person Leonard    schedule 30.03.2009
comment
Я думаю, что на самом деле вас привлекает простота того, о чем они просят. Они не просят вас определить здесь какие-либо каррированные функции, они просто определяют простую концепцию, приложение каррированной функции и просят вас использовать это определение для применения некоторых функций, которые они предоставляют.   -  person Brian Campbell    schedule 30.03.2009


Ответы (6)


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

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

Применением выражения E является выражение вида (E E1 ... En).

Вот пример приложения:

(foo 1 2)      ; This is an application of foo
(bar 1)        ; This is an application of bar

Это включает случай n=0, соответствующий выражению (E).

(baz)          ; This is an application of baz

Curried-приложение E является либо приложением E, либо приложением Curried-приложения E�..........

Это тот, который вы неверно процитировали; выше приведено определение из набора задач, который я нашел в Интернете.

В этом определении есть две половины. Начиная с первого:

Карри-приложение E является либо приложением E

(foo 1 2)       ; (1) A Curried application of foo, since it is an application of foo
(bar 1)         ; (2) A Curried application of bar, since it is an application of bar
(baz)           ; (3) A Curried application of baz, since it is an application of baz

или приложение Curried приложения E

((foo 1 2) 3)   ; (4) A Curried application of foo, since it is an application of (1)
((bar 1))       ; (5) A Curried application of bar, since it is an application of (2)
((baz) 1 2)     ; (6) A Curried application of baz, since it is an application of (3)
(((foo 1 2) 3)) ; A Curried application of foo, since it is an application of (4)
(((bar 1)) 2)   ; A Curried application of bar, since it is an application of (5)
                ; etc...

Дает ли это вам помощь, необходимую для начала?

изменить: Да, (foo1 (sqrt 3)) — это Curried-приложение foo1; это так просто. Это не очень хороший вопрос, так как во многих реализациях вы фактически получите 2.9999999999999996 или что-то в этом роде; невозможно иметь значение, которое будет возвращать ровно 3, если только ваша схема не имеет какого-либо представления точного алгебраического номера.

Ваш второй пример действительно является ошибкой. foo1 возвращает целое число, которое нельзя применять. Только некоторые из более поздних примеров, для которых верен рекурсивный случай применения функции. Взгляните, например, на foo3.

редактировать 2: я только что проверил SICP, и похоже, что концепции здесь не объясняются до раздела 1.3, в то время как в этом задании упоминается только раздел 1.1. Я бы порекомендовал попробовать прочитать раздел 1.3, если вы еще этого не сделали.

person Brian Campbell    schedule 29.03.2009
comment
Я ценю ваш длинный ответ, но признаюсь, я все еще довольно озадачен. Я отредактировал вопрос, чтобы отразить мое текущее состояние замешательства :-) - person Leonard; 29.03.2009
comment
@Брайан. Смотрите мой комментарий в исходном вопросе. Спасибо. - person Leonard; 30.03.2009

См. Что такое "каррирование"?

Каррирование берет функцию и предоставляет новую функцию, принимающую один аргумент и возвращающую указанную функцию с ее первым аргументом, установленным на этот аргумент.

person Eugene Yokota    schedule 29.03.2009
comment
Спасибо. Я прочитал этот вопрос перед публикацией, но я перечитал его сейчас, и во второй раз он имел больше смысла. - person Leonard; 29.03.2009

Большинство ответов, которые вы получили, являются примерами «частичной оценки». Чтобы сделать настоящее каррирование в Scheme, вам нужна синтаксическая помощь. Вроде такой:

(define-syntax curry
  (syntax-rules ()
    ((_ (a) body ...) 
     (lambda (a) body ...))
    ((_ (a b ...) body ...)
     (lambda (a) (curry (b ...) body ...)))))

Который вы затем используете как:

> (define adding-n3 (curry (a b c) (+ a b c)))
> (define adding-n2-to-100 (adding-n3 100))
> ((adding-n2-to-100) 1) 10)
111

> (adding-n3 1)
#<procedure>

> ((adding-n3 1) 10)
#<procedure>
person GoZoner    schedule 28.01.2014

Я не думаю, что функция карри Джеймса верна - когда я пробую ее в своем интерпретаторе схемы, возникает синтаксическая ошибка.

Вот реализация «карри», которую я использую все время:

> (define curry (lambda (f . c) (lambda x (apply f (append c x)))))
> ((curry list 5 4) 3 2)
(5 4 3 2)

Обратите внимание, это также работает для каррирования более одного аргумента функции.

Также есть макрос, который кто-то написал, который позволяет вам писать функции, которые неявно каррируют для вас, когда вы вызываете их с недостаточными аргументами: http://www.engr.uconn.edu/~jeffm/Papers/curry.html

person Paul Hollingsworth    schedule 26.06.2009
comment
+1. Я предпочитаю вашу функцию, даже если я правильно набрал свою, ваша работает лучше. И я должен был проверить, что мои функции работают, извините. - person James Brooks; 28.06.2009

Мне кажется, вы слишком сильно путаете себя. Каррирование функции берет функцию типа F(a1,a2,...aN) и превращает ее в F(a1), которая возвращает функцию, принимающую a2 (которая возвращает функцию, принимающую a3... и т.д.)

Итак, если у вас есть:

(define F (lambda (a b) (+ a b)))
(F 1 2) ;; ==> 3

вы можете каррировать его, чтобы сделать что-то вроде следующего:

(define F (lambda (a) (lambda (b) (+ a b))))
((F 1) 2) ;; ==> 3

в случае вашего конкретного вопроса это кажется очень запутанным.

(foo1 (sqrt 3))

вроде подходит. Я бы порекомендовал оставить это на данный момент и прочитать больше книги.


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

(define (curry f x) (lambda (y) (apply f (cons x y))))
(curry = 0) ;; a function that returns true if input is zero
person James Brooks    schedule 25.06.2009
comment
Кажется, вы неправильно расставили скобки вокруг лямбды. - person Svante; 26.06.2009
comment
Спасибо за часть ((F 1) 2). Помогли мне разобраться с карри! - person Gaʀʀʏ; 30.08.2012

В зависимости от реализации вашей схемы могут быть некоторые утилиты для восстановления после ошибок/исключений, например, в Chicken Scheme есть condition-case.

(condition-case (func)
    ((exn) (print "error")))

Мы можем определить функцию, которая принимает функцию произвольного числа элементов и возвращает каррированную форму:

(define curry
    (lambda (func . args)
        (condition-case (apply func args)
           ((exn)
               (lambda plus
                   (apply curry func (append args plus)))))]))))

Это немного некрасиво, потому что если вы используете слишком много аргументов за один раз, вы никогда не получите окончательный результат, но это превращает любую функцию в каррированную форму.

person Annonyme    schedule 04.03.2013