Scala 如何使用隐式参数实现FRP?

Scala 如何使用隐式参数实现FRP?,scala,functional-programming,reactive-programming,frp,Scala,Functional Programming,Reactive Programming,Frp,我在学习马丁·奥德斯基的。在谈到简单FRP框架的实现时,他首先给出了一个使用StackableVariable(即DynamicVairable)跟踪当前更新信号的框架,我可以理解。但在幻灯片的最后,他提到一个更干净的解决方案是使用隐式参数,而不是DynamicVariable。有人能告诉我怎么做吗?幻灯片的链接对我不起作用。当我试着用谷歌搜索它时,我现在用它作为参考 动态变量是一个线程局部变量,它保存当前评估的信号的状态。这是必要的,以便信号的应用方法能够访问此信息。让我们考虑下面的示例代码:

我在学习马丁·奥德斯基的。在谈到简单FRP框架的实现时,他首先给出了一个使用
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())
    的代码转换为
    Signal.internalApply(隐式触发器dby=>a()+b())
    code。这意味着,
    Signal.apply
    现在是一个宏。这就是scala.rx走过的道路,从使用角度来看,它运行良好。这也允许我们再次写入
    信号(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]