import Control.Monad.State ( State, get, put, evalState ) import Data.FiniteMap ( FiniteMap, lookupFM, addToFM, emptyFM ) {- 最近の処理系なら以下も可.ただし lookup,insert は引数の順序が変わる import Data.Map ( Map, lookup, insert, empty ) -} -- transpose :: [[a]] -> [[a]] リストのリストを行列とみなし転置 -- (例. transpose [[1,2,3],[4,5,6]] == [[1,4],[2,5],[3,6]]) import Data.List ( transpose ) type Table k v = FiniteMap k v type Memo a b = State (Table a b) b memoise :: Ord a => (a -> Memo a b) -> a -> Memo a b memoise f x = do -- 1: table <- get -- 2: 表の取得 case (lookupFM table x) of -- 3: 表の検索 Just y -> return y -- 4: 既に計算済みだった場合 Nothing -> do fx <- f x -- 5: 未済のときは計算 table' <- get -- 6: 表の再取得 put (addToFM table' x fx) -- 7: 表に計算結果を格納 return fx -- 8: 結果を返す runM :: (a -> Memo a b) -> a -> b runM m v = evalState (m v) emptyFM data OpC = Ins Char | Del Char | Subst Char Char | Keep Char type IntOps = (Int, [OpC]) -- 各操作を,変換前の文字,操作を表わす文字,変換後の文字,と長さ 3 の文字列で表現 instance Show OpC where show (Ins c) = ['-', 'v', c ] show (Del c) = [ c, '^', '-'] show (Subst c d) = [ c, '!', d ] show (Keep c) = [ c, ' ', c ] {- -- 結果の表示なしバージョン edM :: (String, String) -> Memo (String, String) Int edM ([], []) = return 0 edM (xs@(_:_), []) = return (length xs) edM ([], ys@(_:_)) = return (length ys) edM xys@(_, _) = memoise edM' xys -- memoise の追加 where edM' (xxs@(x:xs), yys@(y:ys)) = do a <- edM (xs, ys) -- 内部ではメモ化された edM を利用 b <- edM (xxs, ys) c <- edM (xs, yys) return (minimum [ (if x==y then 0 else 1) + a, 1 + b, 1 + c ]) ed_memo :: (String, String) -> Int ed_memo = runM edM -} -- 結果の表示ありバージョン edM :: (String, String) -> Memo (String, String) IntOps edM ([], []) = return (0, []) edM (xs@(_:_), []) = return (length xs, map Del xs) edM ([], ys@(_:_)) = return (length ys, map Ins ys) edM xys@(_, _) = memoise edM' xys where edM' (xxs@(x:xs), yys@(y:ys)) = do (a, ops_a) <- edM (xs, ys) (b, ops_b) <- edM (xxs, ys) (c, ops_c) <- edM (xs, yys) return (min3 (if x==y then (a, Keep x:ops_a) else (1+a, Subst x y:ops_a)) (1+b, Ins y:ops_b) (1+c, Del x:ops_c)) -- 2 つ組の第一要素(fst)だけで順序を決定 min3 :: Ord a => (a,b) -> (a,b) -> (a,b) -> (a,b) min3 a b c = if a `le` b then a `min2` c else b `min2` c where (x, _) `le` (y, _) = x <= y min2 x y | x `le` y = x | otherwise = y ed_memo :: (String, String) -> IntOps ed_memo = runM edM ed_all :: (String, String) -> IO () ed_all xys = do putStrLn $ show d mapM_ putStrLn $ transpose $ map show ops where (d, ops) = ed_memo xys main = ed_all ("mathematical games", "metamagical themas")