2011-10-12 11 views
8

che sto sconcertati cercando di creare l'equivalente di questo banale macro (in Common Lisp) nello Schema MIT:Come si scrive una macro Schema MIT per restituire un modulo lambda?

(defmacro funcify (exp) 
    `(lambda (x) ,exp)) 

Questo è per un semplice progetto personale, un'equazione numerica risolutore basa sulle funzioni incorporate in la seconda conferenza SICP. Non mi interessa che questa macro non sia "sicura" o "igienica" o catturerà una variabile se l'exp fa riferimento a simboli diversi da "x". Mi piacerebbe essere in grado di scrivere

(solv '(* 60 x) '(* 90 (- x 1))) 

dove solv è:

(define (solv lh-exp rh-exp) 
    (solve (funcify lh-exp) (funcify rh-exp))) 

invece di dover digitare

(solve (lambda (x) (* 60 x)) (lambda (x) (* 90 (- x 1)))) 

Ma non riesco a capire come fare questo usando Regole di sintassi del MIT Scheme.

Ho provato questo ma non funziona:

(define-syntax funcify 
    (syntax-rules() 
    ((funcify y) (lambda (x) y)))) 
;Value: funcify 

(funcify x) 
;Value 17: #[compound-procedure 17] 

((funcify x) 10) 
;Unbound variable: x 

Ho provato altre cose, probabilmente non vale la pena menzionare che coinvolge eval ma senza alcun risultato.

Inoltre, i riferimenti a buoni tutorial (non referenze) sul sistema di macro di schema che iniziano con piccoli esempi semplici e si accumulano, con ampio commento, e, in particolare, mostrano come convertire le macro stile backquote-virgola LISP (che per me sono molto intuitivo) al sistema di sintassi della sintassi di Scheme sarebbe grandioso.

risposta

4

Si può fare fondamentalmente la stessa cosa come con defmacro utilizzando explicit-renaming macros . L'unica differenza significativa è che dovrai distruggere il modulo di input da te:

(define-syntax funcify 
    (er-macro-transformer 
    (lambda (form rename cmp) 
     (let ((exp (cadr form))) 
     `(,(rename 'lambda) (x) ,exp))))) 
+0

+1 per l'implementazione ER (supportata dallo Schema MIT). :-) –

+1

@ ChrisJester-Young Grazie per la correzione del bug. :) –

+0

+1. Grazie mille. define-syntax è del tutto sconcertante, ma ho il sospetto che sia molto potente, mi piacerebbe impararlo meglio, ogni riferimento a venire su a velocità su di esso? Accetto la tua risposta perché fornisce una funzionalità che funziona in MIT Scheme, vorrei poter accettare anche la risposta di Chris perché sottolinea anche che solv deve essere una macro di regole di sintassi. – Bogatyr

7

Non può essere eseguito in syntax-rules. Fine della storia.

L'immissione di un identificatore arbitrario (x, nel tuo caso) nell'espressione di output richiede la rottura dell'igiene e syntax-rules non fornisce alcun mezzo per rompere l'igiene. Per fare ciò dovrai usare un sistema macro di livello inferiore. MIT Scheme utilizza ridenominazione esplicito (vedi risposta di Matthias Benkard), ma per altre implementazioni di Scheme che utilizzano syntax-case, si può fare così:

(define-syntax funcify 
    (lambda (stx) 
    (syntax-case stx() 
     ((_ body) 
     (with-syntax ((x (datum->syntax stx 'x))) 
     #'(lambda (x) 
      body)))))) 

La chiave è il bit (datum->syntax stx 'x), che inietta il simbolo x come se fosse nel contesto sintattico del richiamo dello funcify.

A proposito, la tua solv deve essere anche una macro, non una procedura, ma almeno può essere un syntax-rules macro:

(define-syntax solv 
    (syntax-rules() 
    ((_ lhs rhs) (solve (funcify lhs) (funcify rhs))))) 
+0

+1 Grazie mille per la tua risposta, e per sottolineare che il solv deve essere una macro. Le macro sono complicate per cominciare, ma i macro sintassi Scheme- * sono probabilmente la cosa più difficile che ho visto finora in una lingua, e ho programmato (per lo più blubs, ma ho fatto la mia tesi di laurea in CL) per 30+ anni. – Bogatyr

+0

@Bogatyr: aspetta che tu arrivi alle continuazioni. ;-) (Scherzi a parte, però, Scheme è un linguaggio piuttosto grande, concettualmente, nonostante le specifiche R5RS si inseriscano in "50 pagine". –

Problemi correlati