用另一个信号的值过滤一个信号
Filter a signal by the value of another signal
我想为鼠标位置创建过滤 Signal
。它应该在按下鼠标按钮或鼠标从 "not down" 过渡到 "down" 时更新。
我想出了这个功能。它有效,但使用三个匿名函数似乎不对。有惯用的方法吗?
mouseDownPosition: Signal (Int, Int)
mouseDownPosition =
Signal.map2 (\(x, y) isDown -> (x, y, isDown)) Mouse.position Mouse.isDown
|> Signal.filter (\(x, y, isDown) -> isDown) (0, 0, False)
|> Signal.map (\(x, y, isDown) -> (x, y))
在发布问题时,我想出了如何避免匿名函数。不过,我觉得有一个更优雅的解决方案。
mouseDownPosition: Signal (Int, Int)
mouseDownPosition =
Signal.map2 (,) Mouse.position Mouse.isDown
|> Signal.filter snd ((0, 0), False)
|> Signal.map fst
我更喜欢@joews 的解决方案,但只是为了替代,这是另一个版本:
mouseDownPosition: Signal (Int, Int)
mouseDownPosition =
Signal.map2 (\p d -> if d then Just p else Nothing) Mouse.position Mouse.isDown
|> Signal.filterMap identity (0,0)
库函数
有一个名为 signal-extra (full disclosure: I'm the author of that library), which has a function for just this: keepWhen
: Signal Bool -> a -> Signal a -> Signal a
的信号实用程序库。
[...] filter that keeps events from the Signal a
as long as the Signal Bool
is true.
实施
如果你想知道,implementation 和你自己写的几乎一样,但有细微的差别!
keepWhen : Signal Bool -> a -> Signal a -> Signal a
keepWhen boolSig a aSig =
zip boolSig aSig
|> sampleOn aSig
|> keepIf fst (True, a)
|> map snd
zip
只是一个Signal.map2 (,)
来组合两个信号。 keepIf
是 Signal.filter
的旧名称(恕我直言,更清晰)。所以这基本上是一样的。但是把两个信号压缩在一起之后,就有了一个sampleOn
。就在那里,所以过滤的结果是一个信号,它只在原始值信号 aSig
更新时更新,而在 boolSig
更新时不更新。
替代语义
还有一个名为 sampleWhen
: Signal Bool -> a -> Signal a -> Signal a
的过滤器,其描述为:
A combination of Signal.sampleOn
and keepWhen
. When the
first signal becomes True
, the most recent value of the second signal
will be propagated.
此备选方案与您编写的代码相符,但与您的描述不符"Its value should change only when a mouse button is down"。
现在由您决定您真正想要的是哪种行为:)
我想为鼠标位置创建过滤 Signal
。它应该在按下鼠标按钮或鼠标从 "not down" 过渡到 "down" 时更新。
我想出了这个功能。它有效,但使用三个匿名函数似乎不对。有惯用的方法吗?
mouseDownPosition: Signal (Int, Int)
mouseDownPosition =
Signal.map2 (\(x, y) isDown -> (x, y, isDown)) Mouse.position Mouse.isDown
|> Signal.filter (\(x, y, isDown) -> isDown) (0, 0, False)
|> Signal.map (\(x, y, isDown) -> (x, y))
在发布问题时,我想出了如何避免匿名函数。不过,我觉得有一个更优雅的解决方案。
mouseDownPosition: Signal (Int, Int)
mouseDownPosition =
Signal.map2 (,) Mouse.position Mouse.isDown
|> Signal.filter snd ((0, 0), False)
|> Signal.map fst
我更喜欢@joews 的解决方案,但只是为了替代,这是另一个版本:
mouseDownPosition: Signal (Int, Int)
mouseDownPosition =
Signal.map2 (\p d -> if d then Just p else Nothing) Mouse.position Mouse.isDown
|> Signal.filterMap identity (0,0)
库函数
有一个名为 signal-extra (full disclosure: I'm the author of that library), which has a function for just this: keepWhen
: Signal Bool -> a -> Signal a -> Signal a
的信号实用程序库。
[...] filter that keeps events from the
Signal a
as long as theSignal Bool
is true.
实施
如果你想知道,implementation 和你自己写的几乎一样,但有细微的差别!
keepWhen : Signal Bool -> a -> Signal a -> Signal a
keepWhen boolSig a aSig =
zip boolSig aSig
|> sampleOn aSig
|> keepIf fst (True, a)
|> map snd
zip
只是一个Signal.map2 (,)
来组合两个信号。 keepIf
是 Signal.filter
的旧名称(恕我直言,更清晰)。所以这基本上是一样的。但是把两个信号压缩在一起之后,就有了一个sampleOn
。就在那里,所以过滤的结果是一个信号,它只在原始值信号 aSig
更新时更新,而在 boolSig
更新时不更新。
替代语义
还有一个名为 sampleWhen
: Signal Bool -> a -> Signal a -> Signal a
的过滤器,其描述为:
A combination of
Signal.sampleOn
andkeepWhen
. When the first signal becomesTrue
, the most recent value of the second signal will be propagated.
此备选方案与您编写的代码相符,但与您的描述不符"Its value should change only when a mouse button is down"。
现在由您决定您真正想要的是哪种行为:)