Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

controlling evaluation in scheme (guile)

This seems like a simple question; perhaps it is so simple that it is difficult to find a search that will find the answer. In Scheme (specifically, the Guile implementation if that makes any difference) how do I evaluate something that has been quoted?

Here's what I'm trying to do.

I basically need to ensure that a function I define gets its arguments evaluated in a specific order, because side effects caused by evaluating one argument are depended on during the evaluation of other arguments. However, Scheme says arguments can be evaluated in any order, so I want to manually force it by quoting the arguments and then manually evaluating them in the order that is needed.

It appears that "eval" is supposed to do what I want, but it has two problems:

  1. Its use is discouraged, so I feel like there should be a better way to accomplish what I want to do here.
  2. In Scheme it appears that eval takes a second parameter which is the environment. This is confusing to me. I want it to eval in the same environment the statement appears in, so why I should need a second parameter? Is this even possible? I've played with eval a bit and it appears that some implementations requires different parameters (e.g. mit-scheme doesn't even know what (interaction-environment) is!!!)

I've tried other tricks, like building up a lambda:

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

but it appears that this would then have to be evaluated to generate a procedure. I also tried:

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

but this returns a "primitive-builtin-macro" which doesn't work either.

Edit: Looks like a macro will work for controlling order of evaluation: (defmacro test1 (a b) `(begin ,b ,a))

like image 788
Michael Avatar asked Jul 08 '11 23:07

Michael


2 Answers

eval is utterly the wrong tool for just changing the order of evaluation of arguments. Create a macro instead:

;; (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) ....)

Or use defmacro, if you must.

like image 163
Ryan Culpepper Avatar answered Nov 14 '22 11:11

Ryan Culpepper


If you need to evaluate a list structure (nested lists with quoted symbols that represent a Scheme program text), then you should use eval. Scheme requires passing an environment as a second argument, even if it is the current environment:

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

If you just need to do your calculations in a particular order, you can enforce the order of evaluation for side effects by using begin, let, or just a function body. They define a sequence of evaluations:

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

Edit: If you need to have a parametrized block of code where you can pass expressions unevaluated and then force their evaluation in some particular order, then you may use one of these techniques:

  • A macro (as you've mentioned already, just for completeness):

    > (defmacro test1 (a b) `(begin ,b ,a))
    > (test1 (display 2) (display 3)
    32
    
  • A delayed computation (Scheme's special syntax for lazy evaluation):

    > (define (test1 a b) (begin (force b) (force a)))
    > (test1 (delay (display 2)) (delay (display 3)))
    32
    
  • A regular lambda abstraction and application

    > (define (test1 a b) (begin (b) (a)))
    > (test1 (lambda () (display 2)) (lambda () (display 3)))
    32
    
like image 3
Andrey Vlasovskikh Avatar answered Nov 14 '22 09:11

Andrey Vlasovskikh