Haskell的Pipe/Conduit是什麼?
謝邀,Pipe的 primitive version:
data Pipe a b r
= Pure r
| Await (a -&> Pipe a b r)
| Yield b (Pipe a b r)
(&<-&<) :: Pipe b c r -&> Pipe a b r -&> Pipe a c r
Pure r &<-&< _ = Pure r
Yield b p1 &<-&< p2 = Yield b (p1 &<-&< p2)
Await f &<-&< Yield b p2 = f b &<-&< p2
p1 &<-&< Await f = Await $ a -&> p1 &<-&< f a
_ &<-&< Pure r = Pure r
cat :: Pipe a a r
cat = Await $ a -&> Yield a cat
Pure為終止計算;
Yield為emit 計算結果b,以及下一步計算(Pipe a b r),即:Send output data;Await等待輸入a,返回一個計算(Pipe a b r),即:Receive input data。又因為:cat &<-&< p = p -- Right identity
p &<-&< cat = p -- Left identity
(p1 &<-&< p2) &<-&< p3 = p1 &<-&< (p2 &<-&< p3) -- Associativity
故稱之為Pipe category
用stages composition去取代functions composition;可以將計算細化為不同的stages,函數組合變成了狀態/階段的組合,more flexible
more:Pipes.Tutorialport to Scala: arjanblokzijl/scala-pipes
樓上基本說的都很清楚啦,我就說說Conduit和Pipe的區別吧。可以先去看看MonadResource/ResourceT (mtl style transformer),一個嵌入了一張可變釋放表的Reader。
- Conduit內置了和MonadResource的互動,也就是addCleanup這個函數,它可以在某個中間的component跑完的時候,或者下游發生異常提前終止stream的時候,去執行cleanup動作。然後基於這個函數就可以構造一些方便資源管理的函數了(bracketP之類的)。
- Conduit有個專門處理LeftOver的構造函數,用來把這次沒處理完的值返回出來(當然大部分情況下l和i是一樣的),這可以方便的實現io-streams的unRead,但是Pipe要做這個就得引入State了,把leftover記錄在s里,下一個component再去消費。
簡單來說,Conduit就是流計算的一種模型。每一步都有從上游接收和向下游發送兩個類型,以及計算結果類型(注意區別於向下游發送的數據)。每一步按單位進行計算,比如LazyByteString的Chunk,數組的元素等。目的就是避免每一步計算都一次性針對全部數據。
推薦閱讀:
※Kotlin到Dart的簡單翻譯器的坑基本上填完了
※無類型Lambda演算筆記-2(Lambda可定義性,附Haskell實例)
※[C++]代數數據類型與模式匹配