General advice
Once you've run an IO
operation like getMove
your function has to have type IO ????
. Anything that does interaction with the outside world lives in the IO monad, so your function has to have type
completeUserTurn :: Player -> Board -> IO (Maybe (Board, Player))
not
completeUserTurn :: Player -> Board -> Maybe (IO (Board, Player))
The only way to have type Maybe (IO ???)
is to not actually do any IO:
continue :: Bool -> Maybe (IO String)
continue False = Nothing
continue True = Just (putStrLn "Hooray! Please enter a string: " >> getLine)
this function doesn't actually do the getLine
and isn't very useful, as you can check by doing
if isNothing (continue True) then putStrLn "nope" else putStrLn "yes"
in ghci: it never says Hooray. More useful would be
continue :: Bool -> IO (Maybe String)
continue False = return Nothing
continue True = do
putStrLn "Hooray! Please enter a string:\n"
xs <- getLine
return (Just xs)
(Try continue True
and continue False
in ghci)
This one actually does the IO, so it has to have type IO ???
.
Your code
Anyway, your function is better expressed as
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
Both edit #1 and edit #2 are because of the unavoidable change of type to IO (Maybe ??)
.