为了在scheme中模拟简单的OOP(只是为了好玩),我发现自己一遍又一遍地重复以下模式:
(define my-class ; constructor
(let ((let-for-name-encapsulation 'anything))
; object created from data is message passing interface
(define (this data)
(lambda (m)
(cond ((eq? m 'method1) (method1 data))
((eq? m 'method2) (method2 data))
(else (error "my-class: unknown operation error" m)))))
;
(define (method1 data)
(lambda (arg1 ...)
... )) ; code using internal 'data' of object
;
(define (method2 data)
(lambda (arg2 ...)
... ))
;
; returning three arguments constructor (say)
;
(lambda (x y z) (this (list 'data x y z)))))
我决定将所有内容封装在let ((let-for-name-encapsulation ...
中,以避免在全局环境中泄漏名称,同时能够为每个内部函数名称使用define
构造,这增强了可读性。与难看的结构(let ((method1 (lambda (...
相比,我更喜欢这种解决方案,但由于有点人造的let-for-name-encapsulation
,我仍然不太高兴。有人能提出一些简单的建议,让代码看起来更好吗?。我需要学习宏吗?
我经常使用这种模式,但实际上不需要定义任何变量:
(define binding
(let ()
(define local-binding1 expression)
...
procedure-expression)))
我在SRFI的参考实现中看到过它,所以它是一种常见的模式。基本上,这是一种在没有额外标识和lambdas的情况下制作letrec
的方法。它可以很容易地被制作成一个宏,使其更加平坦:
(define-syntax define/lexical
(syntax-rules ()
((_ binding body ...)
(define binding
(let ()
body ...)))))
;; test
(define/lexical my-class
(define (this data)
(lambda (m)
(cond ((eq? m 'method1) (method1 data))
((eq? m 'method2) (method2 data))
(else (error "my-class: unknown operation error" m)))))
(define (method1 data)
(lambda (arg1 ...)
... )) ; code using internal 'data' of object
(define (method2 data)
(lambda (arg2 ...)
... ))
;; returning three arguments constructor (say)
(lambda (x y z) (this (list 'data x y z))))
;; it works for procedures that return procedures as well
(define/lexical (count start end step)
(define ...)
(lambda ...))
当然,您也可以使用宏来简化您的对象系统。