是否Future/Promise模式 能實現的FRP都能更好的實現?
如題。
另外,C#中的Task相關的編程模型算是什麼(更專業的術語)?原諒我無知
我是FRP粉---------------------- 2016-01-16 的回答----------------------------------
frp表現出能夠「消除回調」的能力。但是我用frp來設計系統的時候和我用future來解決問題的時候完全不是一種思維方式。也不覺得在所有場景下FRP的實現都「更好」
-------------------------------------------------------------------------------也許隨著對FRP理解和應用的深入,我會改變答案,或許FRP確實都能實現的更好,從目前的經驗(scala widok, elm-lang,scala future/promise)還不足以讓我認為FRP「都更好」取決於你對Future/Promise模式和FRP的定義。
我自己做過一套 Future/Promise 模式(Stateless Future),提供了非同步計算功能。我也做過一套 FRP 框架 (Binding.scala),提供了數據綁定功能。
然而,我至今還不知道 Future/Promise 模式和 FRP 的精確定義是什麼。我覺得二者的概念上有重複的部分。
但我明確知道,數據綁定和非同步計算肯定不同,這就是我取名 Binding.scala 不叫 React.scala 的原因。如果硬要說有什麼東西可以統一 Future/Promise 模式和 FRP ,我想應該是計算表達式,即 Monad 。所以無論是 Binding.scala 還是 Stateless Future 都可以看成 Monad 。
問題在於,Monad 的基本定義是 point 和 bind 兩個函數。這兩個函數過於底層,上層使用很不方便。直接用 Monad 寫代碼就跟手寫彙編一樣吃力。有沒有辦法像編寫普通代碼一樣使用 Monad ,同時又具備各種數據綁定、非同步計算等黑科技功能呢?
我給出的方案是 Each ,用戶只需要編寫普通命令式語法,就能自動被 Each 轉換成 monadic 風格,無論是 Future 還是 FRP 都不在話下。
最後, @vczh 的編程水平比我預想的還要低啊。C# 的 task 怎麼可能是 comonad ? comonad 要求必須有對表達式立即求值的功能,會導致計算表達式必須是個簡單的值,就喪失了實現各種黑科技的可能了。C#的task叫comonad,但是本質上也是Future/Promise,只是它通過comonad的手段把promise給藏起來了。
我是Scala粉
其實題主問的問題很有價值,學習本身就是將一個個離散的點(概念)聯繫起來的過程,問出這樣的問題並不奇怪,希望能解答題主的疑惑。首先還是得寫點科普的東西Scala的Future是個Monad(twitter的Future也是),抽象為Monad有2個好處(我能想到的):
1. 通過Monad的語義(dependent computation)將多個非同步操作串聯起來,這樣可以有效避免/隱藏回調(onSuccess/onComplete/onFailure...),其次就是隱藏Promise(Scala實現了完整的FuturePromiseCallback模型)2. 可以與其它的Monad(如List, Option)更好的組合(Monad Transformers), 來實現更好的monadic programming,具體的對一個Web應用來說HTTP Request取出的參數無非就是List或Option,對於後端RPC/資料庫請求返回的數據無非也是List/Option(對於輪子哥指出的C# Task是個comonad,我還是不理解,為什麼要對Tasks做coKleisli composition 對下游計算暴露all substructures的好處是啥?世界之大,希望有人來科普。)Scala的Future雖然沒有提供Applicative的實現,但是有sequence組合子,可實現future的橫向組合Scala的Future其語義是代表強非同步計算,也就是每次flatMap組合的future都會被提交到ExecutionContext(默認是forkjoinpool)中,如果希望下游的計算都在同一個線程內完成,可以使用可控性更高的scalaz.concurrent.Task,它需要顯式調用Task.fork才會被提交到池(當然你也可以實現single thread的ExecutionContext)。
(scalaz.concurrent.Task內部實現了trampoline,可控性非常高,可以做Explicit Continuation(自己造的詞),關於這個我還沒仔細研究,有坑回來再填)js的Promise 也是一個Monad(直覺告訴我)
FRP 是一種編程範式,FRP system是對signals的 processors,其first class values是time-varying values (每時每刻都在變化的值),不敢多寫了,怕被邵成大大教育,希望題主也區分一下FRP和RP(否則也會被教育的)。
除了Haskell的FRP庫以及一些語言支持FRP外,其實我們大部分接觸的是RP。RP 可簡單的視為面向事件流的編程的範式,沒有FRP那麼嚴格(還要求behaviors具有明確的指稱語義),下面我也只討論RP
對於形如 a := b + c 指 a的值會隨著b,c不斷變化而變化,如何傳遞變化?那就是把b,c視為被觀察者(Observable),a視為觀察者(Observer),觀察者a收集導致被觀察者b, c的發生改變的事件,a可通過重演事件流確定當前時刻的值,這個事件流的獲取可以是poll/push,同步/非同步,而first class values是event stream一些框架(如Rx*)中的Observable也是一個Monad, 使得我們可以對Observable做combination科普到此就行了,下面來回答問題
是否Future/Promise模式 能實現的FRP都能更好的實現?
引用Rxjs book中的一句話:
Observable is Promise++. A Promise is simply an Observable with one single emitted value. Rx streams go beyond promises by allowing many returned values.
其實這句話已經很好的回答了你的問題,首先解釋Observable is Promise++,從範式和模式的角度來說,Promise去實現RP當然是可行的,而且Promise就是單值(單個離散的事件)的Observable,說白了就是一個一次性的,一個是一直存在的,對於Future也是一樣的,剝離其Monad的語義,Future就是代表這單次的非同步計算,對於下游的計算它就是個Observable
我想它們的關係和區別也已經顯現出來了,一個計算是單次的,一個計算是延續的,後者概念上涵蓋前者,前者是模式,後者是範式,模式可以一定程度上支持範式這也解釋了為啥Finagle (Twitter 的非同步RPC)是響應式的,每個RPC調用都返回一個Twitter的Future,對於RPC的語境(場景),必定是單次計算(request -&> response),Twitter的Future可視為後續計算的Observable
下面討論所謂的「更好」,其實已經沒有必要討論了,因為他們不是對立關係,但是我想說的,所謂的「更好」應該是針對需求方,需求方的使用場景,對於GUI肯定用RP爽,對於簡單的單次非同步計算不需要非用RP
最後說一句,FRP/RP is the future謝邀(本身對這個問題感興趣,最近太忙,拖了好久才答,我不是大神,我只是剛好手頭上的項目是Reactive的,我司也在大量使用Future編程)Rx系列重度用戶,Promise有幸用過一點來說說。Promise能做的用Rx都能做,Promise相當於Rx體系下的一個子集(類似flatMap),完整的Rx體系不能做的遠比Promise多。推薦樓主看下Rxjs,Rxjava,Rxswift之類的庫(跟FRP相關的應用標準庫)。
可以看一下這個: SHOULD use appropriate abstractions only where suitable - Future, Actors, Rx
推薦閱讀:
※如何將MATLAB轉化為C#?
※如何看待2017的 The .NET Language Strategy 去掉了C++/CLI支持?
※什麼情況下使用異常處理?
※C# 中如何有效地釋放內存?
※如何評價微軟推出的 .NET Native?
TAG:C# | 編程範式 | 反應式編程ReactiveProgramming | Promise |