unwrap的奇怪行为(purescript-signal)

问题描述 投票:0回答:1

看一下purescript-signal示例,我看到一个常见的模式是使用纯更新函数和一个有效的渲染函数:

runSignal $ map render (foldp update initialState input)

但是如果渲染需要保持状态,该怎么办,例如因为渲染中有效的渲染操作会返回以下调用渲染所需的值吗?

展开函数看起来像是要走的路,有这样的东西:

unwrap $ foldp render (pure initialRenderState) (foldp update initialState input)

我做了以下代码来尝试解包,但它没有像我预期的那样工作。我期待它打印从0开始的后续整数,它们之间有一秒的延迟。相反,它每秒打印的不仅是新数字,还包括所有以前的数字。

updateEff :: forall eff. Number -> Eff (console :: CONSOLE | eff) Int -> Eff (console :: CONSOLE | eff) Int
updateEff _ stateEff = do
    state <- stateEff
    log $ show state
    pure $ state + 1

main = do
    unwrap $ foldp updateEff (pure 0) (every 1000.0)

同样,这个代码只是尝试解包的一个例子,我知道这些特定的操作可以重写,例如使用纯更新函数和“渲染”函数:runSignal $ map render(foldp update 0(每1000.0))

为什么每次都会重新打印整个数字序列?

purescript
1个回答
1
投票

为什么每次都会重新打印整个数字序列?

似乎使用foldp你正在创建信号,建立越来越大的Eff值。所以例如在第三次迭代之后,你在聚合效果中有这样的东西:

state ← do
  state ← do
    state ← pure 0
    log $ show state
    pure $ state + 1
  log $ show state
  pure $ state + 1
log $ show state
pure $ state + 1

foldp没有运行你的Eff值。另一方面,unwrap根据文档“(...)获取输入信号产生的每个效果并运行它(...)”所以Eff信号产生的foldp值在聚合后最后进行评估,所以我们正在观察积累的影响。

但是如果渲染需要保持状态,该怎么办,例如因为渲染中有效的渲染操作会返回以下调用渲染所需的值吗?

我不确定这是否是最好的方法,但你可以使用purescript-refs的可变引用来保持调用之间的状态 - 这样的事情应该有效:

module Main where

import Prelude

import Control.Monad.Eff.Console (logShow)
import Control.Monad.Eff.Ref (modifyRef, newRef, readRef)
import Signal (unwrap)
import Signal.Time (every)

main = do
  s ← newRef 0
  let
    updateEff _ = do
      readRef s >>= logShow
      modifyRef s (_ + 1)

  unwrap $ map updateEff $ every 1000.0
© www.soinside.com 2019 - 2024. All rights reserved.