Начинающий: функции Curried в схеме - PullRequest
4 голосов
/ 29 марта 2009

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Итак, я могу набрать

((foo1 3 ) 4)

12

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

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

Ответы [ 6 ]

7 голосов
/ 29 марта 2009

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

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

Применение выражения 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 & # 56319; ...........

Это тот, кого вы неверно процитировали; выше - определение из набора проблем, которое я нашел в сети.

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

Применение карри 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

или приложение карри приложения 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...

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

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

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

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

3 голосов
/ 29 января 2014

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

(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>
3 голосов
/ 26 июня 2009

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

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

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

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

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

3 голосов
/ 29 марта 2009

См. Что такое «карри»?

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

2 голосов
/ 25 июня 2009

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

Так что если у вас есть:

(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
0 голосов
/ 04 марта 2013

В зависимости от реализации вашей Схемы, могут быть некоторые утилиты, способные восстанавливаться после ошибок / исключений, например, в Схеме Chicken есть 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)))))]))))

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

...