在使用'定义'时实现名称封装。 over' let'

时间:2016-05-12 19:03:30

标签: 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,我仍然不是很开心。任何人都可以建议一些简单的东西,使代码看起来更好吗?我是否需要学习宏以超越它?

1 个答案:

答案 0 :(得分:3)

我经常使用该模式,但您实际上并不需要定义任何变量:

(define binding
  (let ()
    (define local-binding1 expression)
    ...
    procedure-expression)))

我在SRFI的参考实现中已经看过它,所以它是一种常见的模式。基本上它是一种使letrec没有额外的身份和lambda的方法。它可以很容易地成为一个宏,使它更平坦:

(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 ...))

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