递归更新 a "Behaviour" in Sodium yields 'thread blocked ...'

recursive update a "Behaviour" in Sodium yields 'thread blocked ...'

我会根据其当前值更新行为 (Cell / Val)。

但以下代码抛出一个 线程在 MVar 操作 异常中无限期阻塞。

我预计它会打印三遍 'value of i: '。 我错过了什么? - 谢谢。

  {-# LANGUAGE RecursiveDo #-}
  module Main where

  import           FRP.Sodium

  main :: IO ()
  main = do
    (e, t) <- sync newEvent

    rec
      b <- sync $ hold 0 $ snapshot (\_ i -> i + 1) e b

    sync $ listen (value b) (\i -> putStrLn $ "value of i: " ++ show i)

    sync $ t "ping"
    sync $ t "ping"
    sync $ t "ping"

    return ()

你来自 RecursiveDo 的递归 let 在 IO monad 中。 Reactive monad 还有一个 MonadFix 实例。您可以在 Reactive 中完全定义 b,然后在其周围使用 sync 将整个定义作为事务执行。

main = do
    (e, t) <- sync newEvent

    b <- sync $
        do
            rec
                b <- hold 0 $ snapshot (\_ i -> i + 1) e b
            return b

    sync $ listen (value b) (\i -> putStrLn $ "value of i: " ++ show i)

    ...

RecursiveDo 符号对这么简单的示例没有帮助。用 mfix.

可以更容易地写出同样的事情
main = do
    (e, t) <- sync newEvent

    b <- sync . mfix $ hold 0 . snapshot (\_ i -> i + 1) e

    sync $ listen (value b) (\i -> putStrLn $ "value of i: " ++ show i)

    ...

可能值得一提的是,从 Event 创建 Behavior 通常使用 accum

b <- sync $ accum 0 (const (+1) <$> e)

在 sodium 中,这是一个派生函数,内部定义为 holdsnapshotmfix

accum :: Context r => a -> Event r (a -> a) -> Reactive r (Behavior r a)
accum z efa = do
    rec
        s <- hold z $ snapshot ($) efa s
    return s