わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

Rubyで6÷2(1+2)

6÷2(1+2)は,9か1か…
Rubyで計算させることにしました.
論争のきっかけや,興味深いところを.

先週金曜日の発表では(去年8月の発表でも),RubyとRaccを使って解析したと言ったのですが*1,使い方を忘れてしまったので,手軽なのを探しました…

この中の「syntax.rb」を使うことにしました.
サンプルコードは,現在のRuby 1.8でも1.9でも期待どおりに動きません.デバッグライトで調べていったところ,6行目の

num = (("0".."9")*LOOP1).qualify{|x| x.to_s().to_i()}

num = (("0".."9")*LOOP1).qualify{|x| x.join.to_i()}

とし,10行目の

prim = num.qualify{|x| x[0]} | ("(" + expr + ")").qualify{|x| x[1]}

prim = num.qualify{|x| x} | ("(" + expr + ")").qualify{|x| x[1]}

とすることで,動作するようになりました.
作ったRubyスクリプトは2つです.それぞれ別個に動きます.syntax.rb*2のダウンロードを忘れませんように.

一つめは,加減乗除のほか,「×」を書かない(連接による)乗算と,符号に対応しています*3.なお,連接は乗除よりも優先して計算しますので,6÷2(1+2)は,1と評価します.
もう一つのスクリプトは,実行時にオプションを付けることで,6÷2(1+2)を6÷2×(1+2)とみなして9と評価します…と言いたいのですが,1+2が1(+2)になるという不具合がありまして,符号の処理を取り除いています.
rubyのあと,スクリプトファイルの前に,「-d」オプションをつけて実行すると,評価の順番を見ることができます.

$ ruby -v
ruby 1.8.8dev (2011-03-03) [i386-cygwin]

$ ruby -d pmtd-parser.rb
6÷2(1+2)=
num: x=["6"]:Array, val=6
prim_num: x=6:Fixnum, val=6
prim2: x=[6, []]:Array, val=6
num: x=["2"]:Array, val=2
prim_num: x=2:Fixnum, val=2
num: x=["1"]:Array, val=1
prim_num: x=1:Fixnum, val=1
prim2: x=[1, []]:Array, val=1
expr2: x=[1, []]:Array, val=1
num: x=["2"]:Array, val=2
prim_num: x=2:Fixnum, val=2
prim2: x=[2, []]:Array, val=2
expr2: x=[2, []]:Array, val=2
expr: x=[1, [["+", 2]]]:Array, val=3
prim_par: x=["(", 3, ")"]:Array, val=3
prim2: x=[2, [["", 3]]]:Array, val=6
expr2: x=[6, [["÷", 6]]]:Array, val=1
expr: x=[1, []]:Array, val=1
1

$ ruby -d pmtd-parser.rb -t
6÷2(1+2)=
num: x=["6"]:Array, val=6
prim_num: x=6:Fixnum, val=6
prim2_tw: x=6:Fixnum, val=6
num: x=["2"]:Array, val=2
prim_num: x=2:Fixnum, val=2
prim2_tw: x=2:Fixnum, val=2
num: x=["1"]:Array, val=1
prim_num: x=1:Fixnum, val=1
prim2_tw: x=1:Fixnum, val=1
expr2: x=[1, []]:Array, val=1
num: x=["2"]:Array, val=2
prim_num: x=2:Fixnum, val=2
prim2_tw: x=2:Fixnum, val=2
expr2: x=[2, []]:Array, val=2
expr: x=[1, [["+", 2]]]:Array, val=3
prim_par: x=["(", 3, ")"]:Array, val=3
prim2_tw: x=3:Fixnum, val=3
expr2: x=[6, [["÷", 2], ["", 3]]]:Array, val=9
expr: x=[9, []]:Array, val=9
9

とまあ,スクリプトを書いたところで,私自身はどちらの解釈が良いかについては,『かけ算記号が省略された部分については,優先して計算を行』*4い,6÷2(1+2)=1となるほうが,符号にも対応できてまあ良かったかなといった程度です.教育の観点で言うなら,「6÷2(1+2),学校で子どもに計算させるなら,何年生ですか?」です.

*1:先週そして去年の国際会議発表というのは,SQL文の解析です.ただし,WHERE節の中などに含まれる,式の解析もできるようにしています.

*2:2005年のもので,不安があったものの,一切手を加えることなく,Ruby 1.8/1.9両対応のスクリプトを書くことができました.

*3:"2-3"を与えると-1を,"-2 3"を与えると-6を出力します.なお,"2 - 3"や"2- 3"のように空白を入れると,解釈できない箇所を読み飛ばして,2を評価値とします."(2-3)*2"は-2ですが,"(2 - 3)*2"は実行時エラーとなります.

*4:http://ir.lib.shizuoka.ac.jp/bitstream/10297/996/1/080325001.pdf, p.51