より具体的には、組み込みの Scheme プロシージャの表示をオーバーロードできますか?
より一般的に言えば、Scheme でプロシージャをオーバーロードするにはどうすればよいでしょうか?
より具体的には、組み込みの Scheme プロシージャの表示をオーバーロードできますか?
より一般的に言えば、Scheme でプロシージャをオーバーロードするにはどうすればよいでしょうか?
スキームには、Java/C++ のような型に基づくオーバーロードがありません。動的に型付けされるため、意味がありません。
ただし、いくつかのことができます。
引数の構造に基づいてオーバーロードできます。
(define overload1
(case-lambda
((x y) (+ x y))
((x y z) (+ (- x y) z))))
display
ただし、何があっても1つの引数しかとらないため、これは実際には役に立ちません。
(define (overload-kinda x)
(cond
((list? x) (do-list x))
((symbol? x) (do-sym x))
;etc
))
これはハックですが、必要な場合もあります。
私の通常のアプローチは、高階関数とケース ラムダです。
(define my-display
(case-lambda
((x) (display x))
((x f) (display (f x)))))
何かを表示するために特別な処理が必要な場合は、それをレンダリングする関数を渡します。
受け入れられた答えは、関数をオーバーロードせず、同じ動作で異なる関数を定義するだけです。
通常、Scheme では bultin 関数を上書きすることが許可されているため、関数をオーバーロードするには (例: ) Monkey Patchdisplay
と呼ばれるものを使用できます。
(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 のように適切なオーバーロードになり、のような引数の数に基づくだけではありません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