如何在 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 以下相关内容的屏幕截图。
您阅读这些图表的方式:
- 时间从左流向右。
- 一条线就是一个信号。
- 该块是一个函数,它接受上面的两个信号并产生下面的信号。
- 每行左边的形状为初始值。
- 填充形状是信号上的事件。
- 轮廓形状适用于信号没有变化的情况。
- 我用形状来表示类型。
- 我用颜色来表示不同的值。
请注意,标记为旧行为的第二个图表与 kqr 答案中代码的行为相匹配。
删除了早期版本的 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 以下相关内容的屏幕截图。
您阅读这些图表的方式:
- 时间从左流向右。
- 一条线就是一个信号。
- 该块是一个函数,它接受上面的两个信号并产生下面的信号。
- 每行左边的形状为初始值。
- 填充形状是信号上的事件。
- 轮廓形状适用于信号没有变化的情况。
- 我用形状来表示类型。
- 我用颜色来表示不同的值。
请注意,标记为旧行为的第二个图表与 kqr 答案中代码的行为相匹配。