2016-10-08 42 views
2

我正在學習Martin Odersky的Principles of Reactive Programming。當談到實施一個簡單的FRP框架時,他在開始時給了一個使用StackableVariable(即DynamicVairable)的記錄來跟蹤當前更新的信號,我可以理解。但在幻燈片的末尾,他提到一個更簡潔的解決方案是使用隱式參數而不是DynamicVariable。任何人都可以告訴我如何做到這一點?如何使用隱式參數實現FRP?

+0

我覺得scala.rx不會這樣說:https://github.com/lihaoyi/scala.rx/ blob/master/scalarx/shared/src/main/scala/rx/Core.scala – Reactormonk

+0

鏈接似乎沒有工作,我得到訪問被拒絕的消息 –

回答

3

幻燈片的鏈接不適合我。當我嘗試使用Google搜索時,我現在使用1作爲參考。

動態變量是一個線程局部變量,它保存當前評估信號的狀態。這是必需的,以便Signal的應用方法可以訪問這些信息。讓我們看看下面的示例代碼:

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 

的簽名

Signal[T]#apply()(implicit triggeredBy: Signal[_]) 

(請注意,我們可能需要使用一些新型TriggeredBy代替封裝信號)

這樣,這個方法的實現將有權訪問我ts始發信號沒有全局/線程局部變量。

但是現在我們不得不以某種方式提供這種隱含。一種選擇是也

def Signal.apply[T](fun: => T): Signal[T] 

改變信號的創造功能的簽名

def Signal.apply[T](fun: Signal[_] => T): Signal[T] 

不幸的是,我們的示例代碼的語法有改變的話,因爲我們要提供一個功能而不是身體:

val xPlusY: Signal[Int] = Signal { implicit triggeredBy => a() + b() } 

有這一問題的幾個解決方案:

  • 等到隱式函數類型將被執行2。這可能不會很快發生,但它將使我們能夠寫出如下Signal.apply簽名:

    def Signal.apply[T](fun: implicit Signal[_] => T): Signal[T] 
    

    ,然後可以再次寫入Signal(a() + b())

  • 使用一些宏魔法將表格Signal(a() + b())的代碼轉換爲Signal.internalApply(implicit triggeredBy => a() + b())代碼。這意味着,Signal.apply現在是一個宏。這是scala.rx 3已經走過的道路,從使用的角度來看它運行良好。這也使我們能夠再次編寫Signal(a() + b())

更新:更新鏈接隱函數解釋更詳細的博客artikle

+0

隱式函數類型的東西似乎在Odersky的例子中做了一些奇怪的事情。你確信它也能以你使用它的方式工作嗎? –

+0

好吧,因爲我關於這方面的全部信息來自https://youtu.be/GHzWqJKFCk4?t=47m19s,我沒有找到任何關於它的更多信息,而且它還遠遠沒有實現。我不確定這個例子是否也能起作用,但是我的理解是,它或者至少應該以這種方式工作。 –

+1

@ Jasper-M Martin Odersky發表了一篇新的博客文章,其中明確指出隱式函數類型確實可以按預期工作(但不幸的是僅在dotty中);我更新了文章中的鏈接 –