13. 実装例(Ruby)
def edit_distance(as, bs)
n = as.length
m = bs.length
d = Hash.new {|h, k| h[k] = Hash.new(0)}
for i in 0..n
d[i][0] = i
end
for j in 0..m
d[0][j] = j
end
for i in 1..n
for j in 1..m
delta = as[i] == bs[j] ? 0 : 2
d[i][j] = [d[i-1][j] + 1, d[i][j-1] + 1, d[i-1][j-1] + delta].min
end
end
return d[n][m]
end
• 境界での初期化が必要になる
38. 例:計算順序最適化
• 今度は複数桁に対応してみる
• 必要な演算は加算、乗算、数値、数値の拡張
data Bill = Add Bill Char Bill -- ^ 加算
| Mul Bill Char Bill -- ^ 乗算
| Ext Bill Char -- ^ 数字の桁の続き "123" の 3 の部分
| Val Char -- ^ 数字
deriving (Show, Eq, Ord)
data BillAlg alph ans =
BillAlg { add :: ans -> alph -> ans -> ans
, mul :: ans -> alph -> ans -> ans
, ext :: ans -> alph -> ans
, val :: alph -> ans
, h :: [ans] -> [ans]
}
39. 代数
-- | 数式を pretty print する代数
pretty :: BillAlg Char String
pretty = BillAlg add' mul' ext' val' h'
where
add' x _ y = "(" ++ x ++ " + " ++ y ++ ")"
mul' x _ y = "(" ++ x ++ " * " ++ y ++ ")"
val' c = [c]
ext' i c = i ++ [c]
h' = id
-- | 最小化代数
billMin :: BillAlg Char Int
billMin = BillAlg add' mul' ext' val' h'
where
add' x _ y = x + y
mul' x _ y = x * y
val' c = digitToInt c
ext' i c = i * 10 + digitToInt c
h' [] = []
h' xs = [minimum xs]
• 列挙・数え上げ・最大化も同様
40. 文法
billGrammar :: BillAlg Char ans -> String -> [ans]
billGrammar BillAlg{..} inp = axiom' n bill
where
bill = tabulated $ -- 結果をメモ化する
number
||| (add <<< bill ~~- char '+') ~~~ bill
-- 右側のパーズ結果が一定の文字数を越えないとき ~~- を使う
-- 結合的でないので括弧がついている
||| (mul <<< bill ~~- char '*') ~~~ bill
... h -- 数式それ自体には最適化函数を逐次適用
number = val <<< digit
||| ext <<< number ~~- digit
-- 数値のパーズに h をつけてもしょうがない
-- メモ化する意味も余りない
• メモ化・最適化関数の適用を陽に指定できる強み
• 文法を定義するのでパーズと解生成を一気にできる