[英]Intuition behind the functor in Stream f m r of the streaming library
流媒體庫中Stream
的簡化(無效)定義如下所示:
data Stream f = Step (f (Stream f))
| Return
我想了解引入這個函子f
的動機是什么。
一個典型的這樣的f
是Of a
,其中Of
定義為
data Of a b = !a :> b
deriving Functor
當我在Stream
的定義中將f
讀作Of a
時,這種說法是有道理的, Of ab
類似於a
后跟更多可從b
獲得的東西。 通過這種解釋, Stream 定義中的 f ( Stream
f (Stream f)
讀起來類似於Of a (Stream (Of a))
。 但在這種情況下,一個更簡單的版本應該是
data Stream a = Step a (Stream a)
| Return
我很難理解為什么使用這個仿函數f
的泛化。 在介紹中,作者說Stream
...可用於流式傳輸以任何函子
f
為特征的連續的不同步驟
和
通用類型
Stream fmr
表示一系列步驟……其形狀由“仿函數”參數f
確定。
但是在Streaming.Prelude中,我能找到的唯一仿函數是Or a
、 Stream (Of a) m
和Identity
。 第一個生成a
流,第二個生成流,第三個實現'erasure' 。
我真的不明白。 我可以實現所有這些事情,即a
的簡單流、流的流和擦除,而無需在Stream
中使用這個f
。
這個仿函數f
做了哪些其他事情做不到的事情?
streaming的分組函數的一個關鍵特性是它們不會強制您在任何時候將整個組保存在內存中。 他們以“流式”方式進行分組。 一旦檢測到新組的開始,您就可以開始“下游”處理該組。
例如,想象一個類似lines:: Stream (Of Text) IO r -> Stream (Stream (Of Text) IO) IO r
。 只要該函數在流中檢測到換行符,就會啟動一個新組,即使新行的末尾尚未具體化。
Stream (Stream (Of
Text ) IO) IO r
類型的優點是,要到達當前行之后的行,我們必須完全消耗當前行。 這是因為“流的其余部分”位於仿函數參數的結果值中。 而Stream
只有在用完后才會放棄它們的結果。
像Stream (Of (Stream (Of a) IO ()) IO ()
這樣的類型不會強制我們在移動到下一行之前耗盡當前行。我們可以簡單地忽略在外部Stream
Stream
但是那個“下一行”可能還不存在,因為我們還沒有真正讀過之前的內容,也許這個方案可以以某種方式工作。但是語義會不太清楚並且需要用戶更多的知識。
像mapped
這樣的函數讓我們使用定義為“上游”的“下游”組。 例如,此代碼從stdin讀取字符串,其中字符串“-”是組分隔符。 下游代碼將字符串解析為Int
並在遇到5
時顯示一條消息。 請注意,消息是在組關閉上游之前顯示的。
import Streaming
import qualified Streaming.Prelude as S
example :: Stream (Of ()) IO ()
example =
let upstream :: Stream (Stream (Of String) IO) IO ()
upstream = S.breaks (=="-") S.stdinLn
downstream :: Stream (Stream (Of String) IO) IO ()
-> Stream (Of ()) IO ()
downstream = S.mapped handleGroup
handleGroup :: Stream (Of String) IO r ->
IO (Of () r)
handleGroup stream = do
print "group began"
r <- S.effects
. S.chain (\_ -> putStrLn "found!")
. S.filter (==5)
. S.map (read @Int)
$ stream
print "group ended"
return (() :> r)
in downstream upstream
main :: IO ()
main = S.effects example
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.