haskell - 在 Haskell 中结合 ST 和 List 单子(monad)

标签 haskell state-monad non-deterministic st-monad

使用 StateT monad 转换器,我可以创建类型 StateT s [] a , 与 s -> [(a, s)] 同构.现在我更喜欢使用 STT monad transformer相反,因为我希望拥有多个不同类型的可变变量,并且希望能够根据早期计算的结果随意实例化它们。
但是,STT 的链接文档明确提到:

This monad transformer should not be used with monads that can contain multiple answers, like the list monad. The reason is that the state token will be duplicated across the different answers and this causes Bad Things to happen (such as loss of referential transparency). Safe monads include the monads State, Reader, Writer, Maybe and combinations of their corresponding monad transformers.


那么我的选择是什么?
要完全清楚:
  • 我所追求的是非确定性。我希望能够 fork 我的计算,给每个分支它自己的整个状态的副本。
  • 我不太介意并行性,因为性能不是我最关心的问题。
  • 我不追求的是并发性:不同的计算分支不应该共享可变变量;相反,他们都应该在自己的原始可变变量副本上工作。

  • 编辑:
    (编辑编辑:以下反例无效,因为 ListT 不应应用于非交换单子(monad) STState。)
    我开始意识到 STT monad 转换器,其行为符合 StateT本质上是不安全的。有了它,我们可以构建一个类型 STT sloc (ListT (ST sglob)) a .在这里,sglob是全局状态的名称,而 sloc是本地州的名称。*
    现在我们可以使用全局状态在线程之间交换局部状态引用,从而有可能获得对未初始化变量的引用。
    *为了比较,对应的StateT build 是StateT sloc (ListT (State sglob)) a , 与 sloc -> sglob -> ([(a, sloc)], sglob) 同构.

    最佳答案

    你不会绕过StateT ,因为对于这种不确定性的东西,编译器需要始终知道哪些“变量”需要被分支出来。当变量可能潜伏在 STRef 的任何地方时,这是不可能的。 s。

    要仍然获得“不同类型的多个变量”,您需要将它们打包到合适的记录中,并将其用作单个实际状态变量。处理这样的状态对象似乎很尴尬?嗯,使用镜头访问“个体变量”并没有那么糟糕。

    {-# LANGUAGE TemplateHaskell #-}
    
    import Control.Lens
    import Data.Monoid
    
    import Control.Monad.Trans.State
    import Control.Monad.ListT
    import Control.Monad.Trans.Class
    import Control.Monad.IO.Class
    
    data Stobjs = Stobjs {
        _x :: Int
      , _y :: String
      }
    
    makeLenses ''Stobjs
    
    main = runListT . (`runStateT`Stobjs 10 "") $ do
       δx <- lift $ return 1 <> return 2 <> return 3
       xnow <- x <+= δx
       y .= show xnow
       if xnow > 11 then liftIO . putStrLn =<< use y
                    else lift mempty
    

    (输出 12)。

    “能够随意实例化它们”有点棘手,因为只有通过更改状态对象才能添加变量,这意味着您将不再真正处于同一个 monad 中。镜头有 zooming 的概念可以使用它——将状态对象拆分为“范围”并使用计算,其中只有一些变量被定义为放大到该范围。

    为了使这真正方便,您需要可以随意扩展的记录。我真的很喜欢 Nikita Volkovs record library approach ,这似乎最近没有进一步发展。 Vinyl也朝那个方向发展,但我没有深入研究。

    future ,我们将拥有 OverloadedRecordFields extension这将有助于解决这类问题。

    关于haskell - 在 Haskell 中结合 ST 和 List 单子(monad),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51874362/

    相关文章:

    scala - 在scalaz中将状态分层

    multithreading - 多线程程序可以是确定性的吗?

    haskell - 如何不确定地将值放入状态中?

    项目特定位置的 Haskell 堆栈

    haskell - Common Lisp 中的类型类

    haskell - 什么时候unsafeInterleaveIO不安全?

    haskell - 混合 Threepenny-Gui 和 StateT

    swift - Monads 和 AOP 相关?

    haskell - 将 ST monad 重新打扮成类似于 State monad 的东西

    XML Schema 内容模型是不确定的