Comment detail

呼んだのは誰? (Nested Flatten)
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)]))

Index

Feed

Other

Link

Pathtraq

loading...