2

更具体地说,你能重载内置的 Scheme 过程显示吗?

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

4

2 回答 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
        ))

这是hacky但有时是必要的。

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

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

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

于 2013-04-09T06:00:53.140 回答
0

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

Scheme 通常允许覆盖 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))))))

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

可以将代码抽象为通用宏,该宏将重新定义函数并在特定类型的参数上运行您的代码,因此它将像 Java 中那样进行适当的重载,而不仅仅是像 in 那样基于参数的数量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
于 2021-03-04T12:37:15.783 回答