更具体地说,您能否重载内置Scheme过程display?
更普遍地说,您如何在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
))
这种做法有点取巧,但有时是必要的。
我通常采用高阶函数和 case lambda 方法。
(define my-display
(case-lambda
((x) (display x))
((x f) (display (f x)))))
被接受的答案不会重载函数,只是定义了具有相同行为的不同函数。
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