我要解决的问题是使用Monad创建一个链接列表跟踪,以存储该状态下的水罐,目标,用户输入以及下一个跟踪。
我已经完成了对基本案例的返回和绑定,但是无法弄清楚如何使其适用于递归案例。
import Control.Monad
import Data.Array
import Text.Read
-- Function to run
jugTraceIO :: [Jug] -> Goal -> IO ()
jugTraceIO jugs goal = playTraceIO (T.jugGame (mkJugArray jugs) goal)
-- Function that create the trace
playTraceIO :: (forall m. MonadGame m => m ()) -> IO ()
playTraceIO game = go game >>= printEnding
where
go :: GameTrace () -> IO ()
go (Pure _) = return ()
go (Step jugs goal next) = askPlayer jugs goal >>= \req -> go (next req)
-- Function for user input
askPlayer :: Array Int Jug -> Goal -> IO PlayerMsg
askPlayer jugs (Goal i x) =
printJugs jugs
>> putStrLn ("Goal: Jug #" ++ show i ++ " has " ++ show x ++ "litres.")
>> putStrLn "Please enter which jug to transfer from:"
>> getInt "Please enter which jug to transfer from:"
>>= \src -> getInt "Please enter which jug to transfer to:"
>>= \tgt -> return (FromTo src tgt)
-- Helper Functions
getInt :: String -> IO Int
getInt msg =
putStrLn msg
>> getLine
>>= \inp ->
case readMaybe inp of
Nothing -> putStrLn "Sorry, that's not a number."
>> getInt msg
Just i -> return i
printJugs :: Array Int Jug -> IO ()
printJugs jugs = mapM_ print1 (assocs jugs)
where
print1 (i, Jug cap amt) = putStrLn ("Jug #" ++ show i
++ " capacity=" ++ show cap
++ " amount=" ++ show amt)
mkJugArray :: [Jug] -> Array Int Jug
mkJugArray jugs = listArray (0, length jugs - 1) jugs
-- Data definitions
data PlayerMsg = FromTo Int Int
deriving (Eq, Show)
data Jug = Jug Integer Integer
deriving (Eq, Show)
data Goal = Goal Int Integer
deriving (Eq, Show)
data GameTrace a
= Pure a
| Step (Array Int Jug) Goal (PlayerMsg -> GameTrace a)
-- Test Data
jugArr = [Jug 2 0, Jug 3 0, Jug 4 4]
jugs = mkJugArray jugArr
goal = Goal 0 1
-- Monad Instance
instance Monad GameTrace where
return a = Pure a
Pure a >>= k = k a
Step jugs goal next >>= k = (\f -> k (Step jugs goal (next)))
我希望
Step jugs goal next >>= k = (\f -> k (Step jugs goal (next)))
属于类型
GameTrace a -> (a -> GameTrace b) -> GameTrace b
但实际类型是
GameTrace a -> (a -> GameTrace b) -> t0 -> GameTrace b