Scala 如何使用隐式参数实现FRP?
我在学习马丁·奥德斯基的。在谈到简单FRP框架的实现时,他首先给出了一个使用Scala 如何使用隐式参数实现FRP?,scala,functional-programming,reactive-programming,frp,Scala,Functional Programming,Reactive Programming,Frp,我在学习马丁·奥德斯基的。在谈到简单FRP框架的实现时,他首先给出了一个使用StackableVariable(即DynamicVairable)跟踪当前更新信号的框架,我可以理解。但在幻灯片的最后,他提到一个更干净的解决方案是使用隐式参数,而不是DynamicVariable。有人能告诉我怎么做吗?幻灯片的链接对我不起作用。当我试着用谷歌搜索它时,我现在用它作为参考 动态变量是一个线程局部变量,它保存当前评估的信号的状态。这是必要的,以便信号的应用方法能够访问此信息。让我们考虑下面的示例代码:
StackableVariable
(即DynamicVairable
)跟踪当前更新信号的框架,我可以理解。但在幻灯片的最后,他提到一个更干净的解决方案是使用隐式参数,而不是DynamicVariable
。有人能告诉我怎么做吗?幻灯片的链接对我不起作用。当我试着用谷歌搜索它时,我现在用它作为参考
动态变量是一个线程局部变量,它保存当前评估的信号的状态。这是必要的,以便信号的应用方法能够访问此信息。让我们考虑下面的示例代码:
val a: Signal[Int] = ???
val b: Signal[Int] = ???
val xPlusY: Signal[Int] = Signal(a() + b())
在这里,当调用a()
时,它将自身添加到当前求值信号的依赖项列表中。由于此信息在其他任何地方都无法访问,因此我们基本上使用线程局部a.k.a.全局变量
这个解决方案有几个问题。例如,如果我们不在任何Signal()
内,我们也可以调用a()
。另外,我们必须使用一个全局变量
解决方案是通过一个隐式参数将此信息提供给a()
:我们将签名从
Signal[T]#apply(): T
到
(请注意,我们可能希望使用一些新类型的TriggeredBy
来封装信号)
这样,该方法的实现将能够访问其原始信号,而无需全局/线程局部变量
但现在我们必须以某种方式提供这一隐含信息。一个选项是还将信号创建函数的签名从
def Signal.apply[T](fun: => T): Signal[T]
到
不幸的是,我们的示例代码的语法必须更改,因为我们必须提供函数而不是主体:
val xPlusY: Signal[Int] = Signal { implicit triggeredBy => a() + b() }
有几种解决此问题的方法:
- 等待隐式函数类型的实现。这可能不会很快发生,但它将允许我们编写
信号。应用
签名如下:
然后能够再次写入def Signal.apply[T](fun: implicit Signal[_] => T): Signal[T]
信号(a()+b())
- 使用一些宏魔术将形式为
的代码转换为Signal(a()+b())
code。这意味着,Signal.internalApply(隐式触发器dby=>a()+b())
现在是一个宏。这就是scala.rx走过的道路,从使用角度来看,它运行良好。这也允许我们再次写入Signal.apply
信号(a()+b())
更新:更新了隐式函数链接,对更详细的博客artikle进行了解释我认为scala.rx是这样做的:链接似乎不起作用,我收到了一条访问被拒绝的消息隐式函数类型的事情在Odersky的例子中似乎做了一些奇怪的事情。你有信心它也会以你使用它的方式工作吗?好吧,因为我关于这方面的全部信息都是从观察中获得的,我没有找到任何关于它的进一步信息,而且它离实现还有很长的路要走;我不确定这在这个例子中是否也会起作用,但我的理解是,它也会或至少应该以这种方式起作用。@Jasper-m Martin Odersky的一篇新博客文章明确指出,隐式函数类型确实会如预期的那样起作用(但不幸的是,只在dotty中起作用);我更新了文章中的链接是的,我刚刚看到了。很有见地。
val xPlusY: Signal[Int] = Signal { implicit triggeredBy => a() + b() }
def Signal.apply[T](fun: implicit Signal[_] => T): Signal[T]