如何理解 Edward Kmett 所寫的 machines 這個庫?
github:https://github.com/ekmett/machines/
hackage:http://hackage.haskell.org/package/machines幻燈片:https://dl.dropboxusercontent.com/u/4588997/Machines.pdf簡言之,其與 conduit、pipes 同類,但強調可控多輸入。也 port 到了 scala。
謝邀,這個庫和很多別的流處理的庫差不太多,都是 free 加 step functor 的思路,基本上設計的差異都體現在了 step functor 的選擇上,首先使用 free 來處理 stream 也是一個很傳統的思路:
-- 經典的 Free 定義
data Free f a = Pure a | Free (f (Free f a))
-- 把 Sum type 提出來
data Stream f a = Stream (Step f a (Stream f a))
data Step f a b = Pure a | Layer (f b)
不難看出上面的 Stream 和 Step 構成的數據結構和 Free 是等價的,這裡表達的含義如下:
- Stream 包含了每一步的計算 Step,後續 Stream 在 Step 函子里。
- Step 包含了當前這一步的計算的可能性:每一步要麼產生一個 a 類型的結果(同時終止整個 Stream),要麼產生一個包含在 f 函子類型里的後續 Stream(也就包括了常說的 side effect )。
實際應用的話,上面的 Step 太簡單了,所以才有了各種各樣的設計,machine 的設計如下:
data Step k o r
= Stop
| Yield o r
| forall t. Await (t -&> r) (k t) r
我們來看下每個構造函數分別代表什麼:
- 停止後續 Stream。
- 計算產生 o 類型的輸出和後續的 Stream。
- 包含一個需要
t 類型輸入量的計算和包裹在 k 里的 t,以及上游斷了之後的後續 Stream。這個 k t 的設計是 machine 有意思的地方,本來 t
-&> r 是一個簡單的協程實現:我的這個 Step 需要提供一個 t 才能得到後續的 Stream,但是 k t 的加入使得每個
Step 的 t 來源可以被函子類型 k 參數化,詳見 Wye、Tee、Process 這幾個 machine 提供的函子類型。
machine 還提供了 Plan 這個類型,實際上是 CPS 之後的 machine,你提供幾個情況下的回調,單子實例保證了和別的 machine 組合之後還可以被正確的運行。把握了這個大方向之後,再去看 streaming、list-t 這類的函數庫就很簡單了,基本思路都是類似的。當然 pipes 、conduit 出於效率的原因,直接使用了 CPS 變換,類型稍顯複雜,你可能需要一些簡化的、有注釋的版本:https://github.com/haskell-foundation/foundation/blob/361443295700276cf23fc08af20af80e07ed472c/Foundation/Conduit/Internal.hs#L26。
Welcome to the Machines
推薦這個演講還有Pink Floyd同名的歌
Haskell的Pipe/Conduit是什麼?關於這個問題也可以看看這個演講, 裡面講了這些stream抽象是為了解決什麼問題而誕生的, 但是見面的trade off和design choices還真是要用下才能體會到了推薦閱讀:
※Haskell 有哪些威力十足的庫?
※將 Haskell 翻譯為 Rust, C# (上)標準庫
※一些近期造的輪子
※haskell中的immutable array是如何實現隨機訪問的?
※Haskell 最有代表性的一段程序是什麼?
TAG:Haskell |