方案:重载内置过程,一般重载



更具体地说,您可以重载内置的Scheme过程显示吗?

更一般地说,如何在Scheme中重载任何过程?

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

这是hacky,但有时是必要的。

我通常的方法是使用高阶函数和lambda

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

现在,如果我们需要特殊处理来显示我们传递给函数来呈现它的任何东西

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

方案通常允许覆盖bultin函数,所以要重载函数(例如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

最新更新