可以在不使用可变变量的情况下编码吗?

Ret*_*Fun 3 haskell

考虑以下(非常沉闷)游戏: - 玩家A认为1到100之间的数字. - 玩家B允许5次尝试猜测该数字.玩家A将对每个猜测做出"太大","太小"或"正确"的回应.

我想在Haskell中模拟这个,当然这很简单.但是为了让事情变得有趣,我想以玩家B不能"欺骗"的方式编写代码.这意味着两件事: - 玩家B代码不允许查看密码的正确值.播放器A代码为播放器B代码提供了一个函数,用于检查其猜测. - 不允许玩家B代码调用该函数超过五次.不知何故,播放器A代码必须保持调用函数的次数.

这在使用私有可变变量的OO语言中很容易实现.

在Haskell中,我使用IORef对其进行编码以记录调用次数.那很好,我认为我的解决方案是正确的.但我的问题是:

"如果没有IORef或者类似的话,这可以在Haskell中完成吗?是否有一个我错过的纯功能解决方案?"

这是我的Haskell代码:

import Data.IORef (newIORef, readIORef, writeIORef)
import System.Random (randomRIO)

lowest = 1
highest = 100
maxtries = 5

playerA :: IO (Int -> IO (Maybe Ordering))
playerA = do
    secret <- randomRIO (lowest, highest)
    print ("Secret", secret)
    tries <- newIORef maxtries
    return $ \ guess -> do
        t <- readIORef tries
        if t == 0 then
            return Nothing
        else do
            writeIORef tries $ t - 1
            return $ Just $ guess `compare` secret

playerB :: (Int -> IO (Maybe Ordering)) -> Int -> Int -> IO ()
playerB guessfunc lowbound highbound = do
    let guess = (lowbound + highbound) `div` 2
    response <- guessfunc guess
    print (lowbound, highbound, guess, response)
    case response of
        Just GT -> playerB guessfunc lowbound (guess - 1)
        Just LT -> playerB guessfunc (guess + 1) highbound
        Just EQ -> putStrLn "Player B wins"
        Nothing -> putStrLn "Player B loses"

main :: IO ()
main = do
    guessfunc <- playerA
    playerB guessfunc lowest highest
Run Code Online (Sandbox Code Playgroud)

lef*_*out 11

没有必要这样做IO,你也可以使用纯状态monad:

import Control.Monad.Trans.State
import System.Random (randomRIO)

maxtries = 5

playerA :: IO (Int -> State Int (Maybe Ordering))
playerA = do
   secret <- randomRIO (1,100)
   return $ \guess -> state $ \tries
          -> if tries < maxtries then (Just $ guess`compare`secret, tries+1)
                                 else (Nothing, tries)

playerB :: Monad m => (Int -> m (Maybe Ordering)) -> Int -> Int -> m (Maybe Int)
playerB guessfunc lowbound highbound = do
    let guess = (lowbound + highbound)`div`2
    response <- guessfunc guess
    case response of
        Just GT -> playerB guessfunc lowbound (guess - 1)
        Just LT -> playerB guessfunc (guess + 1) highbound
        Just EQ -> return $ Just guess
        Nothing -> return Nothing

main = do
   pa <- playerA
   print . (`evalState`0) $ playerB pa 1 100
Run Code Online (Sandbox Code Playgroud)

请注意,playerB不知道monad是State Int.这很重要,所以她不能通过在调用之间操纵状态变量来作弊guessfunc.