Использование лямбды с CDR и автомобилем в схеме - PullRequest
0 голосов
/ 08 мая 2019

Я определяю список с помощью кавычек.Затем я пытаюсь определить лямбда-операцию, используя элементы этого списка, которые я получаю с помощью cdr и car.Но заданная лямбда-операция выдает ошибку о количестве параметров.Сообщение об ошибке:

; процедура # [составная-процедура XX] была вызвана с 1 аргументом;для этого требуется ровно 2 аргумента.

(define x '(lambda (n) (+ n 1)))
(cadr x) ;mit scheme interpreter displays (n)
(caddr x) ; this results in (+ n 1)
((lambda (cadr x)(caddr e)) 2) ; this is the problematic part which results in an error.

Решение: создание временной среды и связывание формальных параметров и фактических параметров лямбда-выражений в этой среде и интерпретация тела лямбда-выражения с этой средой.

Ответы [ 2 ]

2 голосов
/ 09 мая 2019

Когда вы делаете:

(define x '(lambda (n) (+ n 1)))

Вы делаете привязку x, чтобы указать на структуру списка (lambda (n) (+ n 1)).Он не имеет ничего общего с lambda формами, такими как:

(define x2 (lambda (n) (+ n 1)))

, где вы можете применить (x2 1) ; ==> 2, поскольку его значение является замыканием / процедурой / функцией, поскольку вычисляется лямбда-форма.

(lambda (cadr x)(caddr e)) не оценивает (cadr x), скорее, он создает замыкание с формальными параметрами cadr и x, так что вы можете применить результат ((lambda (cadr x) ...) 1 2) так, чтобы оценка cadr взакрытие становится 1, а x становится 2.Оценка (caddr e) происходит, когда вы подаете заявку, поэтому, если вы позвоните ((lambda (cadr x)(caddr e)) 'ignored1 'ignored2), она вернет то же, что и оценка (caddr e) в среде, в которой было создано закрытие.Было бы невозможно заставить работать (eval `(lambda ,(cadr x) ,(caddr e))), поскольку у вас не будет возможности обрабатывать свободные переменные, поскольку вы смешиваете хост с вашим гостем.

Поскольку вы создаете интерпретатор, ваши пользовательские процедуры будут структурами данных, и ваш apply будет знать, что с ним делать.Оценка формы должна возвращать что-то, что может быть идентифицировано как замыкание, и вы не можете сделать какой-либо другой код в своем интерпретаторе, чтобы обмануть ее, имеет ссылку на лексическую область места, где она была оценена, и на каждую часть cdrесли лямбда.

Один из моих делает это:

(define closure-tag (list 'closure)) ; make something that is not `eq?` with enything else

(define (closure? expr)
  (and (pair? expr)
       (eq? closure-tag (car expr))))

(define (lambda->closure expr env)
  `(,closure-tag ,env ,@(cdr expr)))

Таким образом, оценка лямбды (lambda (n) (+ n 1)) становится ((closure) ((#t . #t) ...) (n) (+ n 1)) и применяется для ((lambda (n) (+ n 1)) 2), оценивает (+ n 1) с окружающей средой ((n . 2) (#t . #t) ...).Выбор структуры не имеет значения, поскольку структура является соглашением между оценкой лямбда-формы и вашей заявкой.

Вы можете сделать формы lambda процедурами, но это все же не хост-версия гостевого источника, а своего рода оптимизация.Один из моих последних eval сделал это и взял всегда 2 аргумента.Список аргументов неоценен и окружением.В eval lingo примитивы были карри с evlis и apply.Большинство вариантов дизайна, которые вы делаете, будут иметь как преимущества, так и недостатки, и с ними интересно играть.

0 голосов
/ 08 мая 2019

Вам нужно будет использовать EVAL, чтобы превратить указанный код x в фактическую функцию:

((eval x) 2)

или

((eval `(lambda ,(cadr x) ,(caddr x))) 2)
...