在'let'上使用'define'时实现名称封装

  • 本文关键字:实现 封装 let define scheme
  • 更新时间 :
  • 英文 :


为了在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 ...))

当然,您也可以使用宏来简化您的对象系统。

最新更新