2011-07-08 14 views
6

Questa sembra una semplice domanda; forse è così semplice che è difficile trovare una ricerca che trovi la risposta. In Scheme (in particolare, l'implementazione di Guile se questo fa alcuna differenza) come valuto qualcosa che è stato citato?valutazione di controllo in schema (guile)

Ecco cosa sto cercando di fare.

In pratica ho bisogno di garantire che una funzione che definisco ottenga i suoi argomenti valutati in un ordine specifico, perché gli effetti collaterali causati dalla valutazione di un argomento dipendono durante la valutazione di altri argomenti. Tuttavia, Scheme dice che gli argomenti possono essere valutati in qualsiasi ordine, quindi voglio forzarli manualmente citando gli argomenti e quindi valutarli manualmente nell'ordine che è necessario.

Sembra che "eval" è suppone a fare quello che voglio, ma ha due problemi:

  1. Il suo uso è sconsigliato, quindi mi sento come ci dovrebbe essere un modo migliore per realizzare ciò che Voglio fare qui.
  2. In Schema sembra che eval abbia un secondo parametro che è l'ambiente. Questo mi confonde. Voglio che venga valutata nello stesso ambiente in cui appare la frase, quindi perché dovrei aver bisogno di un secondo parametro? È possibile? Ho giocato con eval un po 'e sembra che alcune implementazioni richiedano parametri diversi (es. Mit-scheme non sa nemmeno cosa sia (interazione-ambiente) !!!

Ho provato altri trucchi , come la costruzione di una lambda:

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

ma sembra che questo debba essere valutato per generare una procedura. Ho anche provato:

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

ma questo restituisce un "primitivo-builtin-macro" che non funziona neanche.

Edit: Sembra una macro lavorerà per ordine di valutazione di controllo: (defmacro test1 (ab) `(inizio, B, A))

risposta

1

Se è necessario valutare una struttura di lista (nidificati liste con i simboli quotati che rappresentano un testo del programma Scheme), è necessario utilizzare eval. Scheme è necessario superare un ambiente come secondo argomento, anche se è il contesto attuale:

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

Se avete solo bisogno di fare i vostri calcoli in un ordine particolare, è possibile far rispettare l'ordine di valutazione per gli effetti collaterali, utilizzando begin, let o solo un corpo di funzione.Essi definiscono una sequenza di valutazioni:

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

Edit: Se è necessario disporre di un blocco parametrizzata di codice in cui si può passare espressioni non valutate e quindi forzare la loro valutazione in un certo ordine particolare, allora si può utilizzare uno dei queste tecniche:

  • Una macro (come hai già detto, solo per completezza):

    > (defmacro test1 (a b) `(begin ,b ,a)) 
    > (test1 (display 2) (display 3) 
    32 
    
  • Un calcolo (sintassi speciale del Programma per la valutazione pigra) ritardato:

    > (define (test1 a b) (begin (force b) (force a))) 
    > (test1 (delay (display 2)) (delay (display 3))) 
    32 
    
  • Un regolare astrazione lambda e l'applicazione

    > (define (test1 a b) (begin (b) (a))) 
    > (test1 (lambda() (display 2)) (lambda() (display 3))) 
    32 
    
+0

Come funziona la macro se ho bisogno di un numero variabile di argomenti? '(defmacro test1 (a. b) \' (begin, b, a)) 'non funziona perché b è ora una lista. Ho bisogno di unire in qualche modo all'inizio, ma vari tentativi come '\' (begin (if (pair?, B) (test1, b)), a)) 'non funzionano. – Michael

+0

inoltre, non posso usare '(defmacro test1 (a. B) \' (begin (applica begin, b), a)) 'perché non posso applicare una macro. – Michael

+0

quello che ti sei perso è '(defmacro test1 (a. B) \' (begin, (cons 'begin b), a)) ' –

8

eval è assolutamente lo strumento sbagliato per solo cambiando l'ordine di valutazione di argomenti. Creare una macro invece:

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

Oppure utilizzare defmacro, se è necessario.

0

Sei stato sulla strada giusta con il passaggio in lambda. Se si dispone di

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

... allora si può chiamare in questo modo:

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

Questo chiamerà f con tutti gli argomenti (a, b, c) in una forma non valutata. All'interno di f, hai il pieno potere di scegliere l'ordine in cui li valuti. L'unica differenza è che devi chiamare esplicitamente (x), (y) e (z) e acquisire i loro valori all'interno delle dichiarazioni define o let -like. Questo ti permette di assicurarti che gli effetti collaterali avvengano solo una volta.

Nessun bisogno di macro qui. A proposito, non preoccuparti di usare un sacco di lambda ovunque, sono molto economici.