更具体地说,你能重载内置的 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但有时是必要的。
我常用的方法是高阶函数和 case lambda
(define my-display
(case-lambda
((x) (display x))
((x f) (display (f x)))))
现在,如果我们需要特殊处理来显示任何内容,我们传入一个函数来渲染它。
接受的答案不会重载函数,只定义具有相同行为的不同函数。
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