I've been reading through SICP (Structure and Interpration of Computer Programs) and was really excited to discover this wonderful special form: "make-environment", which they demonstrate to use in combination with eval as a way of writing modular code (excerpt from section 4.3 on "packages"):
我一直在阅读SICP(计算机程序的结构和插入)并且非常兴奋地发现这个奇妙的特殊形式:“make-environment”,他们证明它与eval一起用作编写模块化代码的一种方式(摘录)关于“包裹”的第4.3节:
(define scientific-library
(make-environment
...
(define (square-root x)
...)))
They then demonstrate how it works with
然后他们演示了它的工作原理
((eval 'square-root scientific-library) 4)
In their example, they then go on to demonstrate exactly the usage that I would want - an elegant, minimalist way of doing the "OO" style in scheme... They "cons" together a "type", which is actually what was returned by the "make-environment" special form (i.e. the vtable), and an arg ("the state")...
在他们的例子中,他们继续展示我想要的用法 - 一种优雅,极简主义的方式在计划中做“OO”风格......他们“合作”一起“类型”,这实际上是什么由“make-environment”特殊形式(即vtable)和arg(“the state”)返回...
I was so excited because this is exactly what I've been looking for as a way to do polymorphic dispatch "by symbol" in Scheme without having to write lots of explicit code or macros.
我非常兴奋,因为这正是我一直在寻找的一种方法,可以在Scheme中“按符号”进行多态调度,而无需编写大量显式代码或宏。
i.e. I want to create an "object" that has, say, two functions, that I call in different contexts... but I don't want to refer to them by "car" and "cdr", I want to both declare and evaluate them by their symbolic names.
即我想创建一个“对象”,其中包含两个函数,我在不同的上下文中调用...但我不想通过“car”和“cdr”来引用它们,我想要同时声明并用它们的象征性名称来评估它们。
Anyway, when I read this I couldn't wait to get home and try it.
无论如何,当我读到这篇文章时,我迫不及待想回家试试看。
Imagine my disappointment then when I experienced the following in both PLT Scheme and Chez Scheme:
想象一下,当我在PLT计划和Chez计划中经历以下事件时,我感到很失望:
> (make-environment (define x 3))
Error: invalid context for definition (define x 3).
> (make-environment)
Error: variable make-environment is not bound.
What happened to "make-environment" as referenced in SICP? It all seemed so elegant, and exactly what I want, yet it doesn't seem to be supported in any modern Scheme interpreters?
在SICP中引用了“make-environment”怎么了?这一切看起来都很优雅,而且正是我想要的,但它似乎并没有得到任何现代Scheme解释器的支持?
What's the rationale? Is it simply that "make-environment" has a different name?
理由是什么?简单地说“制造环境”有不同的名称吗?
More information found later
稍后会发现更多信息
I took at look at the online version:
我看了看在线版:
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-28.html#%_sec_4.3
I was reading was the first edition of SICP. The second edition appears to have replaced the discussion on packages with a section on non-deterministic programming and the "amp" operator.
我正在阅读的是SICP的第一版。第二版似乎已经用关于非确定性编程和“放大器”运算符的部分取代了关于包的讨论。
After more digging around I discovered this informative thread on newsnet:
经过更深入的挖掘后,我在新闻网上发现了这个信息丰富的主题:
"The R5RS EVAL and environment specifiers are a compromise between those who profoundly dislike first-class environments and want a restricted EVAL, and those who can not accept/understand EVAL without a second argument that is an environment."
“R5RS EVAL和环境说明符是那些非常不喜欢一流环境并希望限制EVAL的人与那些不能接受/理解EVAL而没有第二个参数即环境的人之间的妥协。”
Also, found this "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)))
(taken from this)
(取自此)
However, I ended up adopting a "message passing" style kinda of like the first guy suggested - I return an alist of functions, and have a generic "send" method for invoking a particular function by name... i.e something like this
然而,我最终采用了“消息传递”风格,有点像第一个人建议 - 我返回一个函数列表,并有一个通用的“发送”方法,用于通过名称调用特定的函数...即这样的东西
(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)
I've been reading further and am aware that there's all of CLOS if I really wanted to adopt a fully OO style - but I think even above is somewhat overkill.
我一直在阅读,并且我知道如果我真的想要采用完全OO风格,那么就有所有CLOS - 但我认为即使上面也有点矫枉过正。
Scheme has no first-class environments because of performance reasons. When Scheme was created, it wasn't the fastest language around due to nifty stuff like first-class functions, continuations, etc. Adding first-class environments would have crippled the performance even further. So it was a trade-off made in the early Scheme days.
由于性能原因,Scheme没有一流的环境。当Scheme被创建时,它不是最快的语言,因为它具有诸如一流函数,延续等等的漂亮东西。添加一流的环境会进一步削弱性能。因此,这是在早期的计划日进行的权衡。
They wrote it like that because MIT Scheme does, in fact, have first-class environments, and presumably that's what the writers were planning to teach their class with (since the book was written at MIT).
他们这样写的是因为麻省理工学院计划确实有一流的环境,并且可能是作家们计划教他们班级的(因为这本书是在麻省理工学院写的)。
Check out http://groups.csail.mit.edu/mac/projects/scheme/
查看http://groups.csail.mit.edu/mac/projects/scheme/
However, I've noticed that MIT Scheme, while still somewhat actively developed, lacks many of the features that a really modern Scheme would have, like a foreign function interface or GUI support. You probably wouldn't want to use it for a serious software development project, at least not by itself.
但是,我注意到MIT Scheme虽然仍然有些积极开发,却缺少真正现代Scheme所具有的许多功能,比如外部函数接口或GUI支持。您可能不希望将其用于严肃的软件开发项目,至少不是单独使用它。
Would a classical dispatcher function work? I think this is similar to what you're looking for.
经典的调度员功能会起作用吗?我认为这与您正在寻找的相似。
(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)
You could even combine the example scientific and fast libraries into one big dispatch method:
您甚至可以将示例科学和快速库组合成一个大型调度方法:
(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)