0

これが私のコードです:

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に入れると思いますか? なぜMaybethen を期待するのですか?

4

2 に答える 2

3

一般的なアドバイス

関数のIOような操作を実行したら、タイプは。でなければなりません。外界と相互作用するものはすべてIOモナドに存在するため、関数にはタイプが必要です。getMoveIO ????

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 ??)

于 2012-11-11T08:44:30.780 に答える
0

IO (Maybe a)もちろん非常に一般的なタイプですが、直接操作するのは面倒です。ただし、モナド変換子MaybeT IO aを使用した場合と同等です。それで、あなたのコードはちょうどなりますMaybeT

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ご覧のとおり、これにより、厄介な明示的なチェックをすべて取り除くことができます。

于 2012-11-11T09:55:40.817 に答える