Внедрение собственной последовательности в рэкет

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

Это то, что у меня есть до сих пор:

(define (foo exp0 exp1 ) exp0 exp1)

person Community    schedule 09.10.2013    source источник
comment
Можете ли вы воспроизвести вопрос, как он звучит в учебнике? То, что вы описываете, - это не функция, а скорее macto. На данный момент у вас есть функция, которая принимает два значения в качестве аргументов, а затем возвращает второе из них.   -  person Joshua Taylor    schedule 09.10.2013
comment
Итак, речь идет о реализации оператора/операции, а не функции. Я просто хотел убедиться в этом. Я вижу, это ваш первый вопрос в StackOverflow. Вы должны иметь возможность редактировать свой вопрос, и добавление такого рода пояснений является хорошим примером того, почему существует такая функциональность. Сейчас я отредактирую его, но в будущем не стесняйтесь обновлять свой вопрос уточнениями; найти проще, да и комментарии не все читают.   -  person Joshua Taylor    schedule 09.10.2013
comment
Почему вы удалили вопрос, который я редактировал (который вы ранее разместили в комментарии)? Он добавил обязательно уточнение. Например, как сказано, это невозможно; вы не можете определить функцию, которая будет это делать. Однако цитируемый вопрос дает понять, что вам нужен оператор, который вы можете определить с помощью define-syntax-rule, как uselpa answer объясняет.   -  person Joshua Taylor    schedule 09.10.2013


Ответы (3)


Предполагая, что у вас есть следующее выражение

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

который будет выполнять формы последовательно.

person uselpa    schedule 09.10.2013
comment
Это не будет работать, так как порядок оценки формы не определен, например. ikarus сначала отобразит c, и это нормально в соответствии со спецификацией. - person Sylwester; 09.10.2013
comment
@Sylwester Как бы вы могли написать процедуру, если бы формы оценивались случайным образом? - person uselpa; 09.10.2013
comment
@Sylwester Я согласен с selpa. Я как бы усложнил проблему в своем ответе, так как думал о том, чтобы аргументы функции оценивались в порядке слева направо. Однако тело функции должно оцениваться в порядке сверху вниз. В противном случае что-то вроде (lambda (x) (display x) (set! x 10)) может либо напечатать 10, либо исходное значение x. - person Joshua Taylor; 09.10.2013
comment
Моя ошибка. Хотя формы 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.

person Joshua Taylor    schedule 09.10.2013
comment
@user1025948 uselpa answer лучше, чем этот. Поскольку я начал с указания на то, что аргументы функции могут оцениваться в любом порядке, я продолжил, показав, как вы можете заставить аргументы функции вычисляться слева направо (таким образом, самым внутренним телом будет вызов функции с переменными ). Однако это необходимо не только для секвенирования. Как указал usepa, вы можете просто сделать формы телом лямбда-выражения. - person Joshua Taylor; 09.10.2013
comment
Это будет работать на одном из языков HtDP, для которого требуется только одна форма в теле лямбда. - person Sylwester; 10.10.2013
comment
@Sylwester Фактически, это был бы способ реализации лямбда-функций, которые могли бы принимать несколько форм в своем теле (просто используйте одноразовые переменные в списках лямбда-аргументов, которые не отображаются в теле). (На самом деле, именно такой подход я использовал при реализации интерпретатора λ-исчисления не так давно…) - person Joshua Taylor; 10.10.2013

Вам нужно что-то, что принимает «одно или несколько выражений», а затем оценивает их и возвращает последнее. Это можно определить с помощью:

(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 ...)))))
person GoZoner    schedule 09.10.2013