Мне нужно реализовать функцию, которая принимает одно или несколько выражений и выполняет эти выражения по порядку.
Это то, что у меня есть до сих пор:
(define (foo exp0 exp1 ) exp0 exp1)
Мне нужно реализовать функцию, которая принимает одно или несколько выражений и выполняет эти выражения по порядку.
Это то, что у меня есть до сих пор:
(define (foo exp0 exp1 ) exp0 exp1)
Предполагая, что у вас есть следующее выражение
(sequence form1 form2 form3)
и вы хотите, чтобы формы оценивались по порядку, тогда вы не можете передать их функции, как объяснил Джосуха. Самым простым преобразованием было бы изменить приведенное выше на
((lambda () form1 form2 form3))
так как формы в лямбда-выражении выполняются последовательно, а результатом является значение последней формы. Поскольку это преобразование должно быть выполнено на уровне исходного кода, вы должны использовать такой макрос, как:
(define-syntax-rule (sequence form1 form2 ...)
((lambda () form1 form2 ...)))
который преобразует такое выражение, как
(sequence (display "a") (display "b") (display "c"))
в
((lambda () (display "a") (display "b") (display "c")))
который будет выполнять формы последовательно.
(lambda (x) (display x) (set! x 10))
может либо напечатать 10
, либо исходное значение x
.
- person Joshua Taylor; 09.10.2013
display
были аргументами, но, поскольку они находятся в теле лямбда, у них есть явное начало и наиболее эффективный способ сделать это.
- person Sylwester; 10.10.2013
Схема не определяет какой-либо конкретный порядок оценки аргументов. Это означает, что если у вас есть функция display-and-return
:
(define (display-and-return x)
(display x)
x)
и затем вы звоните, например,
(list (display-and-return 1) (display-and-return 2))
вы гарантированно получите результат (1 2)
, но вы можете увидеть вывод, созданный display, как 12
или 21
. Однако Scheme указывает, что аргументы функции будут оцениваться до того, как будет оценено тело функции. Итак, вы можете упорядочить два выражения, сделав их аргументами функций:
((lambda (val1)
((lambda (val2)
(list val1 val2))
(display-and-return 2)))
(display-and-return 1))
В общем, вы можете использовать такое преобразование, чтобы превратить (seq exp1 exp2 ... expm expn)
в
((lambda (val1)
((lambda (val2)
...
((lambda (valm)
expn) ; or ((lambda (valn) valn) expn)
expm) ... )
exp2))
exp1)
Вы можете определить такое преобразование, используя define-syntax-rule
.
Вам нужно что-то, что принимает «одно или несколько выражений», а затем оценивает их и возвращает последнее. Это можно определить с помощью:
(define (sequence exp1 . exps)
(car (reverse (cons exp1 exps)))) ; (if (null? exps) exp1 ...)
Затем вы вызовете его как:
> (sequence (+ 1 2) (* 1 2) 17)
17
Использование определения синтаксиса не требуется, поскольку стандартное функциональное приложение будет «выполнять эти выражения по порядку».
Если вам нужно, чтобы порядок был гарантирован слева направо, вам понадобятся:
(define-syntax sequence
(syntax-rules ()
((sequence exp exps ...)
(begin exp expos ...))))
но если вы не можете использовать begin
, но можете использовать lambda
, то:
(define-syntax sequence
(syntax-rules ()
((sequence exp exps ...)
((lambda () exp exps ...)))))
define-syntax-rule
, как uselpa answer объясняет. - person Joshua Taylor   schedule 09.10.2013