呼んだのは誰?
Posted feedbacks - Scheme
Schemeの場合、そもそも関数という概念が抽象的で、gotoの飛び先ラベル程度の 意味しか持たないため、「呼び出した関数」の意味を厳密に決めるのは困難です。 (ナイーブな処理系でも、少なくとも末尾呼び出しについては「ソース上のcaller」の 情報は出せません---出せるようにすると言語仕様を満たせないから) なので、ここではGaucheのMOPを使って通常のSchemeとは違う呼び出し セマンティクスを実現してみます。 実行例: gosh> (define-generic bar :class <tracer>) bar gosh> (define-method bar () (foo)) #<<tracer> 0x8e26940> gosh> (define-generic baz :class <tracer>) baz gosh> (define-method baz () (foo)) #<<tracer> 0x8e26900> gosh> (bar) bar gosh> (baz) baz
1 2 3 4 5 6 7 8 9 10 11 | (use gauche.parameter)
(define call-trace (make-parameter '()))
(define-class <tracer> (<generic>) ())
(define-method apply-generic ((gf <tracer>) args)
(parameterize ((call-trace (cons (ref gf'name) (call-trace))))
(next-method)))
(define (foo) ((every-pred pair? car) (call-trace)))
|
ちなみに下のマクロも仕込んでおけば見かけ上は普通の手続き定義のようになります: gosh> (define (bar) (foo)) #<<tracer> 0x8cc0900> gosh> (define (baz) (foo)) #<<tracer> 0x8cc0880> gosh> (bar) bar gosh> (baz) baz ただ、マクロを使ったら何でもありになってしまいますね。 (マクロ内で手続きのトレース用のラッパーを仕込んでしまう、とか。)
1 2 3 4 5 6 7 8 9 | (use util.match)
(define-macro (define . args)
(match args
[((fn . args) . body)
`(begin
((with-module gauche define) ,fn (make <tracer> :name ',fn))
(define-method ,fn ,args . ,body))]
[(var expr)
`((with-module gauche define) ,var ,expr)]))
|




にしお
#3384()
Rating1/1=1.00
Ruby で表現すると、 以下のような「fooという関数を呼び出す関数」#bar、#bazがあるとき
このbar, bazの返り値が以下のようになるような関数fooを定義してください。このお題は匿名の「Smalltalk からの挑戦状」を元に作成しました。 確かにこの手のリフレクションの機能が言語によってどう違うのかは興味深いところです。 リフレクションを使う問題をいくつか考えてみたいと思います。 ご投稿ありがとうございました。
[ reply ]