这是我的代码:
getMove :: Board -> Player -> IO (Maybe (Move, Board, Player))
completeUserTurn :: Player -> Board -> Maybe (IO (Board, Player))
completeUserTurn player board = do
m <- getMove board player --error is here
if isNothing m then
Nothing
else do
let (move, updatedBoard, updatedPlayer) = fromJust m
if isMoveValid board move then do
continue <- prompt $ displayToUserForPlayer updatedBoard updatedPlayer ++ "\n" ++ "Is this correct? (y/n): "
if continue == "y" then
return (updatedBoard, updatedPlayer)
else
completeUserTurn player board
else do
putStr "Invalid Move!\n"
completeUserTurn player board
这是我得到的错误(在指示的行上):
Couldn't match expected type `Maybe t0'
with actual type `IO (Maybe (Move, Board, Player))'
In the return type of a call of `getMove'
In a stmt of a 'do' block: m <- getMove board player
In the expression:
do { m <- getMove board player;
if isNothing m then
Nothing
else
do { let ...;
.... } }
有什么问题?我虽然<-
会执行IO操作并将结果放入m?为什么期望Maybe
呢?
答案 0 :(得分:3)
运行IO
getMove
之类的操作后,您的函数必须具有IO ????
类型。任何与外界进行交互的东西都存在于IO monad中,因此你的函数必须有类型
completeUserTurn :: Player -> Board -> IO (Maybe (Board, Player))
不是
completeUserTurn :: Player -> Board -> Maybe (IO (Board, Player))
使用类型Maybe (IO ???)
的唯一方法是不实际执行任何IO:
continue :: Bool -> Maybe (IO String)
continue False = Nothing
continue True = Just (putStrLn "Hooray! Please enter a string: " >> getLine)
此函数实际上并不执行getLine
并且不是很有用,因为您可以通过执行检查
if isNothing (continue True) then putStrLn "nope" else putStrLn "yes"
在ghci:它从未说过Hooray。更有用的是
continue :: Bool -> IO (Maybe String)
continue False = return Nothing
continue True = do
putStrLn "Hooray! Please enter a string:\n"
xs <- getLine
return (Just xs)
(在ghci中尝试continue True
和continue False
)
这个实际上是IO,所以它必须有IO ???
类型。
无论如何,你的功能更好地表达为
completeUserTurn :: Player -> Board -> IO (Maybe (Board, Player)) -- new type
completeUserTurn player board = do
m <- getMove board player
if isNothing m then
return Nothing -- edit #1
else do
let (move, updatedBoard, updatedPlayer) = fromJust m
if isMoveValid board move then do
continue <- prompt $ displayToUserForPlayer updatedBoard updatedPlayer ++ "\n" ++ "Is this correct? (y/n): "
if continue == "y" then
return $ Just (updatedBoard, updatedPlayer) -- edit #2
else
completeUserTurn player board
else do
putStr "Invalid Move!\n"
completeUserTurn player board
编辑#1 和编辑#2 都是因为类型不可避免地更改为IO (Maybe ??)
。
答案 1 :(得分:0)
IO (Maybe a)
当然是一种非常常见的类型,但直接使用它很麻烦。但是,使用MaybeT
monad transformer相当于MaybeT IO a
。这样,您的代码就变成了
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
getMove' :: Board -> Player -> MaybeT IO (Move, Board, Player)
getMove' board = MaybeT . getMove board -- with your original `getMove`
completeUserTurn :: Player -> Board -> MaybeT IO (Board, Player)
completeUserTurn player board = do
(move, updatedBoard, updatedPlayer) <- getMove' board player
if isMoveValid board move then do
continue <- lift . prompt
$ displayToUserForPlayer updatedBoard updatedPlayer ++ "\n"
++ "Is this correct? (y/n): "
if continue == "y" then
return (updatedBoard, updatedPlayer)
else
completeUserTurn player board
else do
putStr "Invalid Move!\n"
completeUserTurn player board
如你所见,这让我们摆脱了所有讨厌的明确Nothing
检查。