challenge 呼んだのは誰?

自身を呼び出した関数(メソッド)の名前を返す関数(メソッド)を書いてください。

Ruby で表現すると、 以下のような「fooという関数を呼び出す関数」#bar、#bazがあるとき

def bar; foo end
def baz; foo end
このbar, bazの返り値が以下のようになるような関数fooを定義してください。
bar  #=> "bar"
baz  #=> "baz"

このお題は匿名の「Smalltalk からの挑戦状」を元に作成しました。 確かにこの手のリフレクションの機能が言語によってどう違うのかは興味深いところです。 リフレクションを使う問題をいくつか考えてみたいと思います。 ご投稿ありがとうございました。

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)]))

Index

Feed

Other

Link

Pathtraq

loading...