如何在 Elm 0.15 中获得 keepWhen 行为?

How do I get keepWhen behaviour in Elm 0.15?

删除了早期版本的 Elm 中的 keepWhen 函数。我已经从 0.14 移植了一个 Elm 应用程序,但我一直试图让它的一部分工作,它使用 keepWhen.

所以基本上我在寻找类似

的函数
keepWhen : Signal Bool -> a -> Signal a -> Signal a

我找到了

filter : (a -> Bool) -> a -> Signal a -> Signal a

但这不是一回事,我还没有想出如何让它发挥作用。

我在 Elm 0.15 中根据 Signal.filter 重新实现了 keepWhen。这取决于 Signal.filter 使用信号值来决定是丢弃还是保留信号值的观察结果,以及您可以组合两个信号以获得新信号 (Signal.map2 (,)) 的事实。

如果您将现有的 Signal Bool 与您最终想要的 Signal a 相结合,您将在 Signal.filter 中获得 Signal (a, Bool)提取 Bool 值以决定是否要保留该值。

函数如下所示:

keepWhen : Signal Bool -> a -> Signal a -> Signal a
keepWhen cond def val =
  let combined = Signal.map2 (,) val cond
      filtered = Signal.filter snd (def, False) combined
      final    = Signal.map fst filtered
  in  final

它首先将 "value" 信号与 Bool 信号配对以获得 Signal (a, Bool)。然后它根据其中的 Bool 过滤该信号,最后它剥离 Bool 并仅保留 "real" 值。

你可以在这里看到它的工作:http://share-elm.com/sprout/553c01afe4b06aacf0e8985a。如果您将鼠标靠近 (0,0) 角,它不会更新,但是当您将鼠标移到右下角时,它会再次开始更新信号。

答:从实用程序包导入

最简单的方法是使用 Signal.Extra.keepWhen from the signal-extra 包。
(完全披露:我是作者)

重要的实施细节

请注意,实现并非完全微不足道。这是包中的实现(Signal模块导入不合格):

keepWhen : Signal Bool -> a -> Signal a -> Signal a
keepWhen boolSig a aSig =
  zip boolSig aSig
  |> sampleOn aSig
  |> keepIf fst (True, a)
  |> map snd

中版本的重要区别是 sampleOn 当布尔输入更改时,它会阻止 keepWhen 的输出更新。两个过滤器之间的区别在于,0.14 中的 keepWhen 实际上仅过滤来自 a 输入的更新事件,并且当布尔输入变为 True 时不会对其进行采样。

另一个实现也在 signal-extra 中,名称为 sampleWhen

图表

如果您对弹珠图略有了解,也许 these old diagrams 会有所帮助。我只是 post 以下相关内容的屏幕截图。

您阅读这些图表的方式:

  1. 时间从左流向右。
  2. 一条线就是一个信号。
  3. 该块是一个函数,它接受上面的两个信号并产生下面的信号。
  4. 每行左边的形状为初始值。
  5. 填充形状是信号上的事件。
  6. 轮廓形状适用于信号没有变化的情况。
  7. 我用形状来表示类型。
  8. 我用颜色来表示不同的值。

请注意,标记为旧行为的第二个图表与 kqr 答案中代码的行为相匹配。