gpt4 book ai didi

haskell - 为持续可测量的现象创建行为

转载 作者:行者123 更新时间:2023-12-04 02:18:35 25 4
gpt4 key购买 nike

我想创建一个 Behavior t a来自 IO a ,其预期语义是每次行为为 sample 时都会运行 IO 操作d:

{- language FlexibleContexts #-}
import Reflex.Dom
import Control.Monad.Trans

onDemand :: (MonadWidget t m, MonadIO (PullM t)) => IO a -> m (Behavior t a)

我希望我可以通过执行 measurement 来做到这一点在 pull :
onDemand measure = return $ pull (liftIO measure)

然而,结果 Behavior在初始 measure 之后永远不会改变更换。

我能想出的解决方法是创建一个虚拟 Behavior改变“足够频繁”,然后创建一个虚假的依赖:
import Data.Time.Clock as Time

hold_ :: (MonadHold t m, Reflex t) => Event t a -> m (Behavior t ())
hold_ = hold () . (() <$)

onDemand :: (MonadWidget t m, MonadIO (PullM t)) => IO a -> m (Behavior t a)
onDemand measure = do
now <- liftIO Time.getCurrentTime
tick <- hold_ =<< tickLossy (1/1200) now
return $ pull $ do
_ <- sample tick
liftIO measure

然后按预期工作;但自从 Behavior s 无论如何只能按需采样,这不是必需的。

创建 Behavior 的正确方法是什么?对于一个连续的、随时可观察的现象?

最佳答案

Spider 中执行此操作看起来不可能。 Internal提前推理。

Spider Reflex的实现, 可能的 Behavior 之一s 是拉取值。

data Behavior a
= BehaviorHold !(Hold a)
| BehaviorConst !a
| BehaviorPull !(Pull a)

一个 Pull ed value 包含如何在需要时计算该值, pullCompute ,以及一个缓存值以避免不必要的重新计算, pullValue .
data Pull a
= Pull { pullValue :: !(IORef (Maybe (PullSubscribed a)))
, pullCompute :: !(BehaviorM a)
}

无视 BehaviorM 的丑陋环境, liftIO解除 IO计算方式很明显,它在 BehaviorM 时运行需要采样。在 Pull ,您的行为会被观察一次,但不会被重新观察,因为缓存的值没有失效。

缓存值 PullSubscribed a 由值 a 组成,如果该值无效,则需要使其无效的其他值的列表,以及一些无聊的内存管理内容。
data PullSubscribed a
= PullSubscribed { pullSubscribedValue :: !a
, pullSubscribedInvalidators :: !(IORef [Weak Invalidator])
-- ... boring memory stuff
}

一个 Invalidator 是一个量化的 Pull这足以让内存引用递归地读取无效器以使缓存值无效并将缓存值写入 Nothing。 .

为了不断地拉动,我们希望能够不断地使我们自己的 BehaviorM 失效.执行时,环境传递给 BehaviorM有自己的无效器的副本,由 BehaviorM 的依赖项使用当他们自己变得无效时使其无效。

来自 readBehaviorTracked 的内部实现行为自己的无效器( wi )似乎永远不会出现在采样时无效的订阅者列表中( invsRef )。
    a <- liftIO $ runReaderT (unBehaviorM $ pullCompute p) $ Just (wi, parentsRef)
invsRef <- liftIO . newIORef . maybeToList =<< askInvalidator
-- ...
let subscribed = PullSubscribed
{ pullSubscribedValue = a
, pullSubscribedInvalidators = invsRef
-- ...
}

在内部结构之外,如果确实存在不断采样 Behavior 的方法它将涉及 MonadFix (PullM t)通过修复 pull 实现实例或相互递归和 sample :
onDemand :: (Reflex t, MonadIO (PullM t)) => IO a -> Behavior t a
onDemand read = b
where
b = pull go
go = do
sample b
liftIO read

我没有 Reflex尝试这个的环境,但我不认为结果会很漂亮。

关于haskell - 为持续可测量的现象创建行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35957463/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com