方案:重载内置过程,通用重载

3
更具体地说,您能否重载内置Scheme过程display?
更普遍地说,您如何在Scheme中重载任何过程?
2个回答

3

Scheme没有基于Java/C++那样的类型重载,因为它是动态类型语言,这样做没有意义。

但你可以通过以下方式实现类似的效果:

你可以根据参数的结构进行重载:

(define overload1
    (case-lambda
        ((x y) (+ x y))
        ((x y z) (+ (- x y) z))))

但这并没有帮助到你,因为无论如何display只会接收一个参数。

(define (overload-kinda x)
    (cond
        ((list? x) (do-list x))
        ((symbol? x) (do-sym x))
        ;etc
        ))

这种做法有点取巧,但有时是必要的。

我通常采用高阶函数和 case lambda 方法。

(define my-display
    (case-lambda
        ((x) (display x))
        ((x f) (display (f x)))))

现在,如果我们需要特殊处理来显示任何内容,我们会将一个函数传递给它进行渲染。

0

被接受的答案不会重载函数,只是定义了具有相同行为的不同函数。

Scheme通常允许覆盖内置函数,因此要重载函数(例如display),可以使用称为Monkey Patch的东西:

(define display (let ((orig display))
                  (lambda (x . rest)
                     (let ((port (if (null? rest)
                                     (current-output-port)
                                     (car rest))))
                       (if (number? x)
                           (orig (string-append "#<" (number->string x 16) ">") port)
                           (orig x port))))))

现在显示数字的方式有所不同。您还可以使用自定义类型,以特定方式显示不同类型的记录。这是任何允许修改原始绑定的语言中如何覆盖内置函数的通用示例。您可以将原始函数保存在变量中,重新定义函数,如果要调用原始函数,则使用保存原始函数的变量。

代码可以抽象为通用宏,该宏将重新定义函数并在特定类型的参数上运行您的代码,因此它将是像Java一样的适当重载,而不仅仅基于参数数量,例如case-lambda

以下是使用Lisp类型宏的示例:

(define-macro (overload name-spec . body)
   (let ((name (car name-spec))
         (args (cdr name-spec)))
      `(define ,name (let ((,name ,name))
                       (lambda ,args
                          ,@body)))))

(overload (display x . rest)
   (let ((port (if (null? rest)
                   (current-output-port)
                   (car rest))))
     (if (number? x)
         (display (string-append "#<" (number->string x 16) ">") port)
         (display x port))))

(display 10)
;; ==> #<a>
(display "20")
;; ==>  20

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接