2012年09月

破壊的代入とmultiple-value-bind

僕がLispを美しいと感じるのは、ストレスを感じなく書けるからだと思う。アナフォリックマクロの記事でもそうなのだが、プログラムを書いている最中に不愉快な思考の停止が起こることがあり、これがプログラム中に感じるストレスの最たるものだと思う。ちょっと改変すると途端に問題が起こる上、汚くなる。それを嫌うならば書き直す必要が出てくるのでプログラム効率はかなり落ちる。こういったちょっとした「何でこんなことが出来ないのか!」というのは多々あるが、今回のmultiple-value-bindもそれだ。


先日ソースコードのコメントに”破壊的代入”と書いたら、変なコメント入れないでくださいと言われた。今まで会話の中で普通に破壊的代入という言葉を使ってきたのだが、改めて意味を知っているかと聞くと知らないと言う人が多かった。ていうか、知らないなら聞けよ。


破壊的代入とはCならポインタとか、VBならbyrefとかいう奴のことだ。関数の呼び出し元で渡された変数が、読み出し先の関数で改変されてきてしまう場合だ。


例1

呼び出し元

 a = 3

 plus1(a)


呼び出し先

 void plus1(ref a1)

     a1 = a1 + 1


まぁ、普通一つの値を返すだけの関数ならこんなことをせずに、計算結果を復帰すればよい。明らかにこちらのほうが綺麗であるし、バグが少ない。

例2

呼び出し元

 a = 3

 x = plus1(3)


呼び出し先

 int plus1(a1)

     return a1 + 1

ただし、複数の値を復帰したい場合に、通常の手続き型言語ではそういった機構がなく、やるならばそのためにわざわざ構造体(クラスでも可だが、クラスにした瞬間に参照型になるので破壊的代入と同じになる言語が多い)、型が同一ならば配列を定義する必要がある。そういうのは正直やりすぎなので、例1のようなアプローチを応用するのは仕方が無い。

例3

呼び出し元

 a = 3

 b = 4

 plus1(a,b)


呼び出し先

 void plus1(ref a1,ref b1)

     a1 = a1 + 1

     b1 = b1 + 1


手続き型の言語(大方のオブジェクト指向型含む)は副作用を容認するため仕方が無い。本当は 以下のように書きたいが、文法上不可能である。

 例4 

呼び出し元

 a = 3

 b = 4

 (x,y) = plus1(a,b)


呼び出し先

 void plus1(a1,b1)

     return a1 + 1 , b1 + 1



Lispならばこれで良い。

例4Lispでの実現版


呼び出し元

(let ((a 1) (b 2))
(multiple-value-bind (x y)
  (plus1 a b)))


呼び出し先

(defun plus1(a1 b1)
(values (1+ a1) (1+ b1)))


くどくなるがポイントは

1.呼び出し先で複数の値を復帰できる

2.呼び出し元で複数の値を取得できる

3.すべて値渡しなので副作用は無い(つまり例1ではなく例2のようなアプローチが可能となる)


このようにLispは綺麗でストレスがたまらない言語なのだ。これ読んでLispはじめる人が居たら良いなぁ。いないと思うけど。

王座戦第二局

羽生が後手、久々の四間飛車。後手番での居飛車だったら渡辺に勝てないだろうと思っていたので、俄然勝負が面白くなったように思えた。途中羽生は待ち一方で、8二と9二を交互に指して4手ほどパスしている。将棋をそれなりに指していると、一手パス程度のことは良くやるが、ここまで執拗にパスしまくるのは久しぶりに見た。こういった手番渡しは羽生らしさだろう。渡辺優勢で進みどちらも決め手を与えず終盤で羽生が勝った。手に汗握る将棋だった。羽生渡辺戦というのは華があって面白い。是非とも5戦目まで勝負してほしい。


僕はネット将棋をやるときに、先手番で二手目(つまり後手の初手)が3四歩ならば石田流を指すけど、先手番でもそれ以外の場合は居飛車。後手番では絶対に居飛車を指している。基本的に居飛車党だったのだが、腕が悪いのもあって後手番を引いて相居飛車だと勝率が悪い。振り飛車だから有利になるわけではないと分かってはいるが、今日の羽生を見て後手番振り飛車を試してみたくなった。そういった意味でも良い将棋だった。

最新コメント
QRコード
QRコード
  • ライブドアブログ