code

2016年12月1日 星期四

Scala筆記31 - Functional Reactive Programming

Reactive Programming

其實就是怎麼與使用者互動的編程方式,就是一般我們所說的UI programming,目前主流是MVC model,由於Controller是optional的,可以簡化成subscriber-publisher model。

View subscribes publisher的data,並提供介面給使用者互動。

UI programming主流都是imperative的,event也就是擁有mutable state,並且會有side effect。
結果有人提出了Functional reactive programming,event 不擁有一個mutable state,而是擁有history來包含每個時間點的immutable state。

Signal

scala課程中的FRP把這種有history的event稱為signal,這是scala.React中簡化而來的class。說是signal也正確的,因為那隱含了時間x數值的序列概念。

所以signal其實是一個function,mapping time to value。

一個signal可以知道目前的值,例如現在的滑鼠位置:


以及利用歷史資料定義一個滑鼠位置的signal:


甚至是常數的signal:

val x = Singal(3)

mutable signal of Var

scala也提供了mutable signal,利用Signal的subclass Var來實做一個instance:


scala中,indexed assignment事實上是呼叫update方法的syntatic sugar,例如array 中以下兩行是等效的:

val x = Array(1,2,3)
x(0) = 100x.update(0,100)


我們說signal是一個function,mapping時間到value,而他擁有的current value function例如mousePosition(),事實上是一個dereferencing function,所以以下的寫法是會造成cyclic definition,因為我們是在定義一個function,卻以他自己的本來的定義定義之:

mousePosition() = mousePosition() + 5


Bank Account Example

class BankAccount {
  val balance = Var(0)

  def deposit(amount:Int):Unit = {
    if (amount > 0) {
      val b = balance()
      balance() = b + amount //dereference and update    }
  }

  def withdraw(amount:Int):Unit = {
    if (amount > 0 && amount <= balance()) {
      val b = balance()
      balance() = b - amount
    }
    else throw new Error("錢不夠啦")
  }

}

可以看到balance是一個Var[Int],不過這樣又如何?

先來看怎麼使用:

def consolidated(accounts:List[BankAccount]) :Signal[Int] =
  Signal(accounts.map(_.balance()).sum)


val a = new BankAccount()
val b = new BankAccount()
val c = consolidated(List(a,b))

c() //0a.deposit(20)
b.deposit(20)
c() //40

所以可以看到consolidated這個function實際上是一個signal function,這個signal function跟隨著每個帳戶的即時bank account變動,但那又如何?其實有點observer的味道了。

signal比較有趣的地方是,另一個signal可以combine某一個signal,當然其值也同步變化,上面consolidated是一個這樣的伴隨變化,以下這個匯率的signal:

val exchange = Signal(30.0)
val dollar = Signal(exchange() * c())
dollar() //1200a deposit 100c() //140dollar() //4200

我們做了一個新的signal叫dollar,他的value隨著另外兩個signal的某時刻的value的乘積變化。其實目前看來都還好,感覺上沒什麼特別的?!


沒有留言:

張貼留言