是否可以在State monad中使用IO,而不使用StateT和ST

时间:2015-08-25 20:48:42

标签: haskell monads state-monad

在下面的代码中,我管理一个拥有链接列表的游戏。 在游戏的每一步,我都会更改游戏状态,更新修改后的链接列表。

当我正在学习State monad时,我试图将State monad技术应用于此用例。

尽管如此,在每个回合中,我都需要使用getLine

从IO获取一条信息

这给出了这样的代码

{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
import Control.Monad
import Control.Monad.State.Strict
import qualified Data.List as List
import qualified Control.Monad.IO.Class as IOClass

type Node = Int 
type Link = (Node,Node)
type Links = [Link]
type Gateway = Node
type Gateways = [Gateway]

data Game = Game { nbNodes :: Int, links :: Links, gateways :: Gateways }

computeNextTurn :: State Game Link
computeNextTurn = do
    g <- get
    inputLine <- IOClass.liftIO getLine -- this line causes problem
    let node = read inputLine :: Int
    let game@(Game _ ls gs) = g
    let linkToSever = computeLinkToSever game node
    let ls' = List.delete linkToSever ls
    let game' = game{links = ls'}
    put game'
    return linkToSever

computeAllTurns :: State Game Links
computeAllTurns = do
            linkToSever <- computeNextTurn
            nextGames <- computeAllTurns
            return (linkToSever : nextGames)

computeLinkToSever :: Game -> Node -> Link
computeLinkToSever _ _ = (0,1) -- just a dummy value
        -- this function doesnt compute really anything for the moment
        -- but it will depend on the value of node i got from IO

但是我在编译时遇到错误:

  

(MonadIO Data.Functor.Identity.Identity)没有实例        使用liftIO

引起的

如果我尝试使用liftMlift,我会遇到同样的错误。

我已经阅读了一些建议StateTST的问题,我还没有掌握这些问题。

我想知道我现在的技术状态是否注定会失败,而且我确实无法使用State,而是StateT / ST

或者是否可以在getLine monad中从State获取值?

1 个答案:

答案 0 :(得分:3)

正如@bheklilr在评论中所说,你不能使用来自State的IO。其原因基本上是State(这只是StateT优于Identity的简写)并不神奇,所以它不能再使用

  • 你已经可以在它的基础monad Identity
  • 中做些什么
  • State本身提供的新操作

但是,第一点也暗示了解决方案:如果您将基本monad从Identity更改为其他monad m,那么您将能够使用{{1}提供的效果}}。在您的情况下,通过将m设置为m,您就可以了。

请注意,如果您的计算部分需要执行IO,但需要访问您的州,您仍然可以通过使其类型为

IO

然后,您可以使用foo :: (Monad m) => Bar -> StateT Game m Baz 中的计算编写foo,但其类型也明显表明它不可能执行任何IO(或其他任何基于monad特定的任何内容)。

您还在问题中提到了StateT Game IO作为可能的解决方案。 ST不是monad转换器,因此不允许您从某些基础monad导入效果。