Reverse State monad的现实生活和有用的例子

She*_*rsh 9 haskell lazy-evaluation state-monad

反向状态monad是非常好的,令人兴奋的Haskell语言表达性和懒惰评价的例子.但要理解这个单子并不容易.此外,很难找到一些令人信服的现实生活中的例子,说明你可以使用Reverse State monad比使用该语言中的任何其他工具更容易.

反向状态 monad的定义方式如下:

newtype RState s a = RState { runRState :: s -> (a,s) }

instance Monad (RState s) where
    return x = RState $ (,) x
    RState sf >>= f = RState $ \s ->
        let (a, past)   = sf future
            (b, future) = runRState (f a) s
        in (b, past)
Run Code Online (Sandbox Code Playgroud)

它已经有一些例子和用法,但我发现它们并不实用.

  1. Quora回答:很好地解释,甚至有现实生活中的使用例子但没有代码,并且不清楚它是否是一个非常好的主意RState.
  2. Mindfuck:介绍这个很好的概念但是例子没用.没有人会这样写斐波那契数字.
  3. Kwang的Haskell博客:展示如何Writer模仿,RState但来吧.不是真正的生活例子:)

我也知道tardis包但没有这个库的教程,文档示例真的是抽象的,没有那么多人真正理解它.最接近我想要的是本教程,但它有一个例子tardis,而不仅仅是RState.以及本书的参考资料.

因此,我不是在寻找tardis真实的生活模式,RState如果可能的话,我只对插图感兴趣.虽然我明白可能没有纯粹RState用法的样本.在那种情况下,最小的例子与RStateT变压器或tardis足够好.

有人在现实生活中使用过这个monad,或者是否有非常好用且有用的插图代码?

小智 5

我已经知道这些单子了十多年了,直到最近才看到它们的实际应用。这是一个不寻常的设置。我和一个同事正在通过'reflex'库使用功能性反应式编程,并且正在使用一个库来帮助构建终端图形应用程序。如果您熟悉'reflex-dom',则本质上类似,只是我们的基本monad而不是将后续小部件一个接一个地放置在DOM中,而是将基于终端字符单元的“图像”堆叠在顶部彼此之间的区别,取决于用户是否合理地切割屏幕。我们想提供比这更好的东西,这可以在某种程度上跟踪剩余的屏幕房地产,并让用户放置一些“平铺”

除了处理布局问题外,我们还希望这些图块能够管理键盘焦点,从而允许用户按Tab键在它们之间循环,或使Tab键倒转。正是在这里,时间向前和向后状态monad转换器变得非常方便:我们可以使任一方向上的当前状态成为一个事件(一个空元组)。每个磁贴都可以将事件发送到上一个和下一个小部件(并从中接收事件),在它们获得键盘焦点时通知小部件,因此应停止阻止按键到达其子小部件。如此示意,瓦片小部件看起来像:

do rec focusP <- recvFromPast
       sendToPast shiftTabPress
       tabPress <- gate focused $ ... filter input Event for Tab keypresses ...
       shiftTabPress <- gate focused $ ... filter input Event for Shift-Tab ...
       focused <- hold False $ leftmost
         [ True <$ (focusP <> focusF)
         , False <$ (shiftTabPress <> tabPress) ]
       v <- ... run the child widget and do layout stuff ...
       sendToFuture tabPress
       focusF <- recvFromFuture
   return v
Run Code Online (Sandbox Code Playgroud)

在这里,sendToFuture是普通状态“ put”,sendToPast是反向状态“ put”,recvFromPast是普通状态“ get”,recvFromFuture是反向状态“ get”。因此focusP :: Event t (),我们从前任那里得到的一个事件(可能focusF是另一个类似的事件)告诉我们我们现在有重点了,并且,这是我们从后任那里得到的一个类似事件。我们使用'hold'构造跟踪焦点的时间focused :: Behavior t Bool,然后将其用于门控键盘事件,这样我们可以确保仅当我们自己集中精力时告诉邻居他们正在获得焦点,并且我也忽略了我们在运行子窗口小部件的位置,以便适当地过滤其输入事件。

我不确定在发布库时我们实际上是否仍会以这种方式进行操作,但是到目前为止它似乎运行良好,我很高兴终于注意到这种情况可能是投入实际使用。