Haskellでチューリングマシン(2) テープの処理をモナドに

前回のエントリのテープに対する処理を、モナドに包んだだけです。

module Machine(TapeValue(..)) where

--テープの値は 0 または 1
data TapeValue = T0 | T1 deriving Eq
instance Show TapeValue where
  show T0 = "0"
  show T1 = "1"

--無限長の長さを持つテープ
data Tape = Tape [TapeValue] [TapeValue] deriving Eq
instance Show Tape where
  show (Tape front forward) =
    toStr (reverse front) ++ "|" ++ show (head forward) ++ "| " ++ toStr (tail forward)
    where toStr l = concat $ map (\v -> show v ++ " ") l

--チューリングマシンモナド 
data TuringMachine a = TuringMachine a deriving (Show,Eq)
instance Monad TuringMachine where
  return a = TuringMachine a
  (TuringMachine x) >>= f = f x

initTape :: TuringMachine Tape
initTape = TuringMachine $ Tape [] [T0]

--テープの移動
moveFront :: Tape -> TuringMachine Tape
moveFront (Tape [] forward) = TuringMachine $ Tape [] (T0 : forward)
moveFront (Tape front forward) = TuringMachine $ Tape (tail front) (head front : forward)

moveForward :: Tape -> TuringMachine Tape
moveForward (Tape front (position : [])) = TuringMachine $ Tape (position : front) [T0]
moveForward (Tape front forward) = TuringMachine $ Tape (head forward : front) (tail forward)

--書き込み
writeTape :: TapeValue -> Tape -> TuringMachine Tape
writeTape val (Tape front forward) = TuringMachine $ Tape front (val : tail forward)

--読み込み
readTape :: Tape -> TuringMachine TapeValue
readTape (Tape _ v) = TuringMachine $ head v

プログラムのデータとかも作り始めてるので、エクスポート文が中途半端だったりします。

実行結果

*Machine> initTape >>= moveFront >>= writeTape T1
TuringMachine |1| 0 
*Machine> it >>= moveFront >>= writeTape T1 >>= moveForward >>= writeTape T0
TuringMachine 1 |0| 0 
*Machine> it >>= moveForward >>= moveForward >>= writeTape T1
TuringMachine 1 0 0 |1| 
*Machine> it >>= moveForward >>= writeTape T1 >>= moveFront >>= writeTape T0 >>= moveFront >>= writeTape T1
TuringMachine 1 0 |1| 0 1 

的確な使いどころかどうかまだ今ひとつ解ってないのですが、安全性も上がったし簡潔になったし、可読性もわりと良いので、よしとしましょう。

ところで、最近 Real World Haskell を読んでいるのですが・・・

Real World Haskell―実戦で学ぶ関数型言語プログラミング

Real World Haskell―実戦で学ぶ関数型言語プログラミング

これによると、Show型のインスタンスで直接出力形式を整えるのは良くないみたいですね・・・
ひと通りプログラムができたら、プリティプリンタで出力するように書き換えましょうか。