Perché Scheme non supporta ambienti di prima classe?
Domanda
Ho letto tramite SICP (Struttura e interpretazione dei programmi per computer) ed ero davvero entusiasta di scoprire questa meravigliosa forma speciale: "make-environment", che dimostrano di usare in combinazione con eval come modo di scrivere codice modulare (estratto dalla sezione 4.3 su "pacchetti"):
(define scientific-library
(make-environment
...
(define (square-root x)
...)))
Dimostrano quindi come funziona
((eval 'square-root scientific-library) 4)
Nel loro esempio, continuano poi a dimostrare esattamente l'uso che vorrei - un modo elegante e minimalista di fare il "OO" stile nello schema ... Essi "contro". insieme un "tipo", che in realtà è ciò che è stato restituito dal "make-environment" forma speciale (cioè la vtable) e un arg ("lo stato") ...
Ero così eccitato perché questo è esattamente quello che stavo cercando come un modo per fare un invio polimorfico "per simbolo". nello schema senza dover scrivere un sacco di codice esplicito o macro.
vale a dire. Voglio creare un " oggetto " che ha, diciamo, due funzioni che io chiamo in contesti diversi ... ma non voglio fare riferimento a loro con "auto" e " cdr " ;, voglio sia dichiarare sia valutarli con i loro nomi simbolici.
Comunque, quando ho letto questo non vedevo l'ora di tornare a casa e provarlo.
Immagina la mia delusione quando ho provato quanto segue sia nello schema PLT che nello schema Chez:
> (make-environment (define x 3))
Error: invalid context for definition (define x 3).
> (make-environment)
Error: variable make-environment is not bound.
Che cosa è successo a " make-environment " come indicato in SICP? Sembrava tutto così elegante, ed esattamente quello che voglio, eppure non sembra essere supportato in nessun moderno interprete di Scheme?
Qual è la logica? È semplicemente quel "make-environment"? ha un nome diverso?
Ulteriori informazioni trovate in seguito
Ho dato un'occhiata alla versione online:
http: // mitpress .mit.edu / SICP / full-text / libro / book-ZH-28.html #% _ sec_4.3
Stavo leggendo la prima edizione di SICP. La seconda edizione sembra aver sostituito la discussione sui pacchetti con una sezione sulla programmazione non deterministica e l'amplificazione & amp; operatore.
Soluzione
Dopo ulteriori ricerche ho scoperto questo thread informativo su newsnet:
" R5RS EVAL e gli specificatori di ambiente sono un compromesso tra coloro che non amano molto gli ambienti di prima classe e vogliono a EVAL limitato e coloro che non possono accettare / comprendere EVAL senza un secondo argomento che è un ambiente. "
Inoltre, ho trovato questo " work-around " ;:
(define-syntax make-environment
(syntax-rules ()
((_ definition ...)
(let ((environment (scheme-report-environment 5)))
(eval '(begin definition
...)
environment)
environment))))
(define arctic
(make-environment
(define animal 'polarbaer)))
(tratto da questo )
Tuttavia, ho finito per adottare un messaggio che passa " stile un po 'come il primo ragazzo ha suggerito: restituisco una lista di funzioni e ho un generico "invia" metodo per invocare una particolare funzione per nome ... cioè qualcosa di simile
(define multiply
(list
(cons 'differentiate (...))
(cons 'evaluate (lambda (args) (apply * args)))))
(define lookup
(lambda (name dict)
(cdr (assoc name dict))))
; Lookup the method on the object and invoke it
(define send
(lambda (method arg args)
((lookup method arg) args))
((send 'evaluate multiply) args)
Ho letto di più e sono consapevole che c'è tutto CLOS se volessi davvero adottare uno stile completamente OO - ma penso che anche sopra sia un po 'eccessivo.
Altri suggerimenti
Lo schema non ha ambienti di prima classe per motivi di prestazioni. Quando è stato creato Scheme, non era il linguaggio più veloce in circolazione a causa di cose ingegnose come funzioni di prima classe, continuazioni, ecc. L'aggiunta di ambienti di prima classe avrebbe compromesso ulteriormente le prestazioni. Quindi è stato un compromesso fatto nei primi giorni dello Schema.
L'hanno scritto in questo modo perché il MIT Scheme ha, di fatto, ambienti di prima classe, e presumibilmente è quello con cui gli scrittori stavano progettando di insegnare alla loro classe (da quando il libro è stato scritto al MIT).
Scopri http://groups.csail.mit.edu/mac/ progetti / programma /
Tuttavia, ho notato che il MIT Scheme, sebbene ancora in qualche modo sviluppato attivamente, manca di molte delle caratteristiche che avrebbe uno Schema davvero moderno, come un'interfaccia di funzione esterna o il supporto della GUI. Probabilmente non vorrai usarlo per un serio progetto di sviluppo software, almeno non da solo.
Una funzione di dispatcher classico funzionerebbe? Penso che questo sia simile a quello che stai cercando.
(define (scientific-library f)
(define (scientific-square-root x) (some-scientific-square-root x))
(cond ((eq? f 'square-root) scientific-square-root)
(else (error "no such function" f))))
(define (fast-library f)
(define (fast-square-root x) (some-fast-square-root x))
(cond ((eq? f 'square-root) fast-square-root)
(else (error "no such function" f))))
((scientific-library 'square-root) 23)
((fast-library 'square-root) 23)
Potresti anche combinare le biblioteche scientifiche e veloci di esempio in un unico metodo di spedizione:
(define (library l f)
(define (scientific-library f)
...)
(define (fast-library f)
...)
(cond ((eq? l 'scientific) (scientific-library f))
((eq? l 'fast) (fast-library f))
(else (error "no such library" l))))
(library 'fast 'square-root)