読者です 読者をやめる 読者になる 読者になる

Mae向きなブログ

Mae向きな日記のブログ版。ようやくこちらに移行してきました。

27章分の21章

今日は,『プログラミングGauche』の

  • 19章 継続(昨日からの継続…)
  • 20章 モジュールシステム
  • 21章 デバッグ

を読みました。

19章

昨日,読んでほとんど意味が分からなかったので,今日も取り組んでいます。
http://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A の中で,

しかし継続の概念は、ほとんどの (SchemeRuby を除く) プログラミング言語では明示的に扱われていない。

とありましたので,今日はちょっと趣向を変えて,Rubyで継続について勉強してみます。
Rubyで継続で末尾再帰最適化まがいの行為をした」にcallccを用いた1+2+3+…+nを求めるプログラムがありました。以下です。

def sum(n)
  acc = 0
  cc = nil
  callcc {|i| cc = i}
  case n
  when 0 then acc
  else n, acc = n - 1, acc + n; cc.call
  end
end

puts sum(10)

ccはContinuationクラスのインスタンスなので,cc.callとすることで,case n以下を実行するんだろうと思います(nが0になったら停止です)。なんとなく,ほんの少し継続についてイメージがわいてきたので,Gaucheで書いてみたのが,以下です。

(define (sum n)
  (let ((acc 0) (cc #f))
    (call/cc
     (lambda (i)
       (set! cc i)))
    (cond [(eq? n 0) acc]
          [else
           (set! acc (+ acc n))
           (set! n (- n 1))
           (cc)])))

Ruby版の1行1行をそのまま書いてみました。実行すると,一応動きます。

gosh> (sum 10)
55

21章

P332に「21.7 マクロの調査」があります。その中で,aifをマクロ定義しているのですが,この中で使われている「@」は何の意味があるのでしょう?

(define-macro (aif test-form then-form . else-form)
  `(let ((it ,test-form))
     (if it ,then-form ,@else-form)))

不思議に思って,「@」無しのaif2も定義してみました。

(define-macro (aif2 test-form then-form . else-form)
  `(let ((it ,test-form))
     (if it ,then-form ,else-form)))

aifとaif2を実行してみます。

gosh> (define m '(shiro nobsun yasuyuki cut-sea))
m
gosh> (aif (member 'yasuyuki m)
           (car it) "Not Found")
yasuyuki
gosh> (aif2 (member 'yasuyuki m)
           (car it) "Not Found")
yasuyuki

両者に違いはありません…。しかし,「@」はelse-formについていたので,以下を試してみると,

gosh> (aif (member 'rahaema m)
           (car it) "Not Found")
"Not Found"
gosh> (aif2 (member 'rahaema m)
           (car it) "Not Found")
*** ERROR: invalid application: ("Not Found")

両者に違いが現れました。macroexpandで展開してみると,

gosh> (macroexpand
       '(aif (member 'rahaema m)
             (car it) "Not Found"))
(let ((it (member 'rahaema m))) (if it (car it) "Not Found"))
gosh> (macroexpand
       '(aif2 (member 'rahaema m)
              (car it) "Not Found"))
(let ((it (member 'rahaema m))) (if it (car it) ("Not Found")))

となりました。
しかし,この「@」,探し方が悪かったんだろうと思うのですが,本の中にもGaucheユーザリファレンスにも説明を見つけることはできませんでした…。

追記

上記の件ですが,id:SaitoAtsushiさんに教えていただきました。ありがとうございます。
http://practical-scheme.net/gauche/man/gauche-refj_30.html#IDX68 を見て理解しました。