【问题标题】:How to print the result of a State Monad in Haskell?如何在 Haskell 中打印 State Monad 的结果?
【发布时间】:2016-04-15 19:05:38
【问题描述】:

是否可以在 Haskell 中打印状态单子的结果?

我正在尝试理解状态单子,并且在我一直关注的一本书中提供了以下用于创建状态单子的代码,但我在这个主题上苦苦挣扎,因为我无法直观地查看该过程,即查看最终结果.

newtype State s a = State { runState :: s -> (a,s)}

instance Monad (State s) where  
    return x = State $ \s -> (x,s)  
    (State h) >>= f = State $ \s -> let (a, newState) = h s  
                                        (State g) = f a  
                                    in  g newState

【问题讨论】:

  • “如何打印状态单子”与“如何打印状态单子的 result”是一个完全不同的问题,至少如果我将前者理解为打印State 动作 和后者作为打印一次执行State 动作的结果。你是什​​么意思?
  • @leftaroundabout 结果抱歉。

标签: haskell monads


【解决方案1】:

通常不可能以有意义的方式打印函数。如果函数的域很小,您可以从universe-reverse-instances 包中导入Data.Universe.Instances.Show 以获得一个Show 实例,该实例打印一个在语义上与该函数等效的查找表。导入该模块后,您可以简单地将 deriving Show 添加到您的 newtype 声明中,以便能够在较小的状态空间上打印 State 操作。

【讨论】:

    【解决方案2】:

    您提供的代码定义了State s a种类。它还说State s 是一个单子——也就是说,State s 的那种东西符合Monad 类型类/接口。这意味着您可以将一个 State s 计算绑定到另一个计算(只要每个 s 的类型相同)。

    因此,您的情况类似于某人定义了 Map 的类型,并且还编写了代码,表明 Map 符合某某接口,但谁没有任何地图,并且尚未使用它们运行任何计算。那么就没有什么可打印的了。

    我认为您想查看评估或执行状态操作的结果,但您尚未定义任何实际状态操作,也没有在它们上调用runState(或evalStateexecState) .不要忘记您还需要提供初始状态来运行计算。

    所以也许首先让sa 成为一些特定类型。例如。让s 成为Int 并让a 成为Int。现在你可以去写一些 fns,例如f :: Int -> (Int, Int)g :: Int -> (Int, Int)。也许一个函数递减状态,返回新的状态和值,而另一个函数递增状态,返回新的状态和值。然后您可以通过将f 包装在State 构造函数中来制作State Int Int。您可以使用>>= 将任意数量的状态操作链接在一起。最后,您可以在此使用runState 来获取结果值和结果状态,只要您还提供初始状态(例如 0)。

    【讨论】:

    • @liminalishit 非常感谢您的回答,它真的很有帮助!我制作了一个函数 f 来增加状态。我有点不确定如何做链条部分对不起,你可以给我看一个例子吗?谢谢
    • f = \x -> (x+1, x+1),让g = State (f) >>= State (f)。这表示将状态增加两次的状态操作。 runState g 0 应该返回 (2,2)。等效地,如果 h = \x -> return (x+1, x+1),并且 j = StateT (h) >>= StateT (h),则 runStateT h 0 返回 (2,2)。这可能会让您了解State monad 的工作原理。但是使用 get putmodify 构建状态动作,从像 mtltransformers 这样的包,通常是你将如何使用 State monad,并且真的类似于你可能的命令式风格习惯于使用命令式语言。
    【解决方案3】:

    如果这只是你想要的结果,如果你只是在调试:

    import Debug.Trace
    import Control.Monad.Trans.State
    
    action :: State [Int] ()
    action = do
      put [0]
      modify (1:)
      modify (2:)
      get >>= traceShowM
      modify (3:)
      modify (4:)
      get >>= traceShowM
    

    【讨论】:

    • 谢谢,但我得到的错误不在 put、modify、modify、get、modify、modify、get 的范围内?
    • 这是使用库提供的函数,可通过导入 Control.Monad.Trans.State 访问
    • 谢谢,我收到一条错误消息“不明确的出现 'State' 它可能指的是 'Main.State' 或 'Control.Monad.Trans.State.State'”? @古尔肯格拉斯
    • State 已经在 transformers 包中定义,如果你想使用包的版本,你必须注释掉你的版本。或者,您可以重新实现 get 和 put
    • 运行动作函数时出现错误(Show (State [Int] ()))?
    猜你喜欢
    • 1970-01-01
    • 2022-11-22
    • 2013-05-16
    • 2018-08-27
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多