контрольная оценка в схеме (лукавство) - PullRequest
6 голосов
/ 09 июля 2011

Это кажется простым вопросом;возможно, это так просто, что трудно найти поиск, который найдет ответ.В Схеме (в частности, в реализации Guile, если это имеет какое-то значение), как мне оценить то, что было процитировано?

Вот что я пытаюсь сделать.

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

Похоже, что "eval" это предполагается делать то, что я хочу, но у него есть две проблемы:

  1. Его использование не рекомендуется, поэтому я чувствую, чтодолжен быть лучший способ выполнить то, что я хочу сделать здесь.
  2. В Схеме кажется, что eval принимает второй параметр, который является средой.Это смущает меня.Я хочу, чтобы он вычислялся в той же среде, в которой появляется оператор, так зачем мне нужен второй параметр?Это вообще возможно?Я немного поиграл с eval, и похоже, что в некоторых реализациях требуются разные параметры (например, mit-схема даже не знает, что такое (среда взаимодействия) !!!)

пробовал другие приемы, такие как построение лямбды:

(list 'lambda '() '(car (b c)))

, но похоже, что это должно быть оценено для генерации процедуры.Я также пытался:

(list lambda '() '(car (b c)))

, но это возвращает "примитив-встроенный макрос", который тоже не работает.

Редактировать: похоже, макрос будет работать для контроля порядка вычисления: (defmacro test1 (ab) `(begin, b, a))

Ответы [ 3 ]

8 голосов
/ 09 июля 2011

eval - совершенно неправильный инструмент для изменения порядка вычисления аргументов. Вместо этого создайте макрос:

;; (my-fun e1 e2)
;; Just calls my-real-fun, but evaluates e2 before e1
(define-syntax my-fun
  (syntax-rules ()
    [(my-fun e1 e2)
     ;; let* has guaranteed order of evaluation
     (let* ([y e2]
            [x e1])
       (my-real-fun x y))]))

(define (my-real-fun x y) ....)

Или используйте defmacro, если необходимо.

2 голосов
/ 09 июля 2011

Если вам нужно оценить структуру списка (вложенные списки с символами в кавычках, которые представляют текст программы Scheme), тогда вы должны использовать eval. Схема требует передачи среды в качестве второго аргумента, даже если это текущая среда:

(eval '(+ x y) (interaction-environment))

Если вам просто нужно выполнить расчеты в определенном порядке, вы можете применить порядок оценки побочных эффектов, используя begin, let или просто тело функции. Они определяют последовательность оценок:

(let ((x 42))
  ; eval with effects #1
  (display x)
  ; eval with effects #2
  (display (+ x 1)))

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

  • Макрос (как вы уже упоминали, только для полноты):

    > (defmacro test1 (a b) `(begin ,b ,a))
    > (test1 (display 2) (display 3)
    32
    
  • Вычисление с задержкой (специальный синтаксис схемы для отложенных вычислений):

    > (define (test1 a b) (begin (force b) (force a)))
    > (test1 (delay (display 2)) (delay (display 3)))
    32
    
  • Обычная лямбда-абстракция и применение

    > (define (test1 a b) (begin (b) (a)))
    > (test1 (lambda () (display 2)) (lambda () (display 3)))
    32
    
0 голосов
/ 28 января 2014

Вы были на правильном пути с прохождением в лямбдах. Если у вас есть

(define (f x y z) ...)

... тогда вы можете назвать это так:

(f
  (lambda () a)
  (lambda () b)
  (lambda () c))

Это вызовет f со всеми аргументами (a, b, c) в неоцененной форме. Внутри f у вас есть полная возможность выбрать порядок их оценки. Единственное отличие состоит в том, что вы должны явно вызывать (x), (y) и (z) и фиксировать их значения внутри define или let -подобных операторов. Это позволяет вам гарантировать, что побочные эффекты случаются только один раз.

Здесь нет необходимости в макросах. Кстати, не беспокойтесь об использовании большого количества лямбд везде, они очень дешевые.

...