【问题标题】:Creating Applicative instance of a stateful signal type with Elerea使用 Elerea 创建有状态信号类型的应用实例
【发布时间】:2014-10-09 02:35:11
【问题描述】:

我在Helm 中四处乱窜,试图创建一个有状态的信号类型,该类型将携带有关自上次采样以来值是否已更改的附加信息。我已经设法使新信号类型成为Functor 的实例,但我正在努力定义Applicative<*> 函数,这将允许我将多个信号提升到一个函数中。

到目前为止,我定义的唯一信号是constant 信号,它在初始采样时将具有Changed x,之后将具有Unchanged x。其他信号会更复杂,并使用Elerea.stateful 来确定值是否已更改。

lift2 在下面的代码中不起作用,因为尚未定义 <*>

import qualified FRP.Elerea.Simple as Elerea
import Control.Applicative

data Event a = Changed a | Unchanged a

instance Functor Event where
    fmap f (Changed a)   = Changed (f a)
    fmap f (Unchanged a) = Unchanged (f a)

instance Applicative Event where
    pure = Unchanged
    (Changed   f) <*> (Changed   x) = Changed (f x)
    (Changed   f) <*> (Unchanged x) = Changed (f x)
    (Unchanged f) <*> (Changed   x) = Changed (f x)
    (Unchanged f) <*> (Unchanged x) = Unchanged (f x)

data Signal a = Signal (Elerea.SignalGen (Elerea.Signal (Event a)))

instance Functor Signal where
    fmap f (Signal x) = Signal ((fmap . fmap . fmap) f x)

instance Applicative Signal where
    pure = Signal . pure . pure . pure
    --(<*>) = ??

{-| Creates a signal that never changes. -}
constant :: a -> Signal a
constant x = Signal $ Elerea.stateful (Changed x) (\_ -> Unchanged x)

lift :: (a -> b) -> Signal a -> Signal b
lift = fmap

lift2 :: (a -> b -> c) -> Signal a -> Signal b -> Signal c
lift2 f a b = fmap f a <*> b

我目前正在使用的完整代码位于 Github

【问题讨论】:

  • 为什么Signal 包含SignalGen
  • 所以 Elerea 定义了 Elerea.SignalElerea.SignalGen。 Elerea 中的信号是无事件的,只是恒定的值流。我正在尝试定义一个新的信号类型,更接近信号的Elm 想法,可用于确定主元素是否需要重新计算和重新渲染(当值自上次采样以来发生变化时)。
  • 另见Helm issue(赏金由我创建)。
  • 也许更清楚:Elerea.stateful 返回一个 Elerea.SignalGen (Elerea.Signal a),我正在尝试包装它。

标签: haskell frp elerea


【解决方案1】:

pure . pure . pure的签名是:

(Applicative f, Applicative f1, Applicative f2) => a -> f (f1 (f2 a))

所以你只想通过两个额外的应用层来提升&lt;*&gt;。您需要一个带有签名的函数:

(Applicative f, Applicative f1, Applicative f2) => f (f1 (f2 (a -> b))) -> f (f1 (f2 a)) -> f (f1 (f2 b))

这个功能可以通过两次申请liftA2来实现,所以请试试这个:

(Signal f) <*> (Signal x) = Signal $ (liftA2 (liftA2 (<*>))) f x

【讨论】:

  • 行得通!非常感谢您的回答并解释您到达那里的思考过程。自我注意:始终查看类型。
猜你喜欢
  • 2012-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多