2011-07-08 4 views
6

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

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

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

Оказывается, что «Eval» является должен делать то, что я хочу, но у него есть две проблемы:

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

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

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

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

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

но это возвращает «примитивные встроенная_команда_оболочки-макро», который не работает.

Edit: Похоже макрос будет работать для контроля порядка оценки: (defmacro test1 (аb) `(начало, б, а))

ответ

1

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

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

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

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

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

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

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

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

Как работает макрос, если мне нужно переменное количество аргументов? '(defmacro test1 (a. b) \' (begin, b, a)) 'не работает, потому что b теперь является списком. Мне нужно как-то вставить его в начало, но различные попытки, такие как '\' (begin (if (pair?, B) (test1, b)), a)) 'не работают. – Michael

+0

также, я не могу использовать '(defmacro test1 (a. B) \' (begin (apply begin, b), a)) ', потому что я не могу применить макрос. – Michael

+0

тот, который вы пропустили, - '(defmacro test1 (a. B) \' (begin, (cons 'begin b), a)) ' –

8

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, если необходимо.

0

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

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

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

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^