Yampa 支持记忆信号功能吗?

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

我在Yampa中编写了一个基本信号函数,如下:

sf :: SF Int Int
sf = arr $ \x -> trace "1 * 2 = 2" (x * 2)

该函数将其输入加倍,并向控制台打印“1 * 2 = 2”以表明它已被调用。然后我用下面的代码测试了 sf:

embed sf (deltaEncode 1 (repeat 1))

如您所见,仅提供值 1 作为 sf 的输入。我希望 Yampa 具有某种形式的记忆功能,以防止使用相同的输入重复调用 sf,因为传递给

arr
的函数应该是纯函数。然而,似乎没有这样的支持,因为“1 * 2 = 2”被重复打印。

为了提供更多背景信息,我有一些使用 React 进行响应式编程的经验,并且我目前正在探索 FRP 的概念。 Yampa 是我选择的第一个 FRP 库,我希望在 Yampa 中找到类似于 React 的

memo
的东西来有效地处理重新计算。我在 Hoogle 中搜索了
a -> b -> SF a b
,找到了
arrPrim
。但它也没有达到我的预期。

在扬帕有办法实现这一目标吗?如果没有,Yampa 如何高效执行信号函数?

此外,我提供的示例不涉及时变系统,因为它只是忽略了时间。我最初认为 Yampa 对于仅离散事件系统也很有用,如果它至少提供类似

memo
的东西。然而,如果这样的东西不存在,那么我相信 Yampa 可能只对时变系统有用。这个理解准确吗?

由于我仍处于学习FRP的早期阶段,我担心我可能误解了一些概念。如果您能澄清任何误解或推荐其他更符合我期望的 FRP 库,我将不胜感激。

haskell signals frp yampa arrow-abstraction
1个回答
3
投票

在 Haskell 中,没有默认的记忆函数。 Haskell 的惰性工作原理是值默认是不可变的,因此除非您使用不同的变量,否则不会重新计算。在这种情况下,函数被记忆,但其结果未被记忆。这是因为在幕后,您正在输入列表上调用此函数:

$ ghci
Prelude> let xs = take 5 $ repeat 1
Prelude> import Debug.Trace
Prelude Debug.Trace> let f x = trace "hi" $ x * 2
Prelude Debug.Trace> f <$> xs
[hi
2,hi
2,hi
2,hi
2,hi
2]

由于每个输入都是不同的,因此没有记忆。但是,您可以非常直接地记住您自己的函数。只需使用状态信号函数来跟踪最后的输入,使用

sscanPrim
:

-- test.hs
import FRP.Yampa
import Debug.Trace

memoized :: Eq a => a -> (a -> b) -> SF a b
memoized x0 f = sscanPrim memo x0 (f x0)
  where
    memo old new | old == new = Nothing
                 | otherwise = Just (new, f new)

sf :: SF Int Int
sf = memoized 1 $ \x -> trace "1 * 2 = 2" (x * 2)
--

$ ghci test.hs
*Main> take 10 $ embed sf (deltaEncode 1 (repeat 1))
[1 * 2 = 2
2,2,2,2,2,2,2,2,2,2]
© www.soinside.com 2019 - 2024. All rights reserved.