[英]What is the connection between Iteratees and FRP?
在我看來,這兩個想法之間存在着密切的聯系。 我的猜測是,如果有一種方法可以用迭代器表示任意圖形,那么FRP可以用Iteratees來實現。 但是afaik他們只支持鏈式結構。
有人可以對此有所了解嗎?
這是相反的方式。 AFRP和流處理之間存在很強的聯系。 事實上,AFRP 是流處理的一種形式,你可以使用這個習慣來實現與管道非常相似的東西:
data Pipe m a b =
Pipe {
cleanup :: m (),
feed :: [a] -> m (Maybe [b], Pipe m a b)
}
這是Netwire中的電線類別的擴展。 它接收下一個輸入塊並在停止生成時返回Nothing。 使用此文件閱讀器將具有以下類型:
readFile :: (MonadIO m) => FilePath -> Pipe m a ByteString
Pipe是一系列應用函子,所以要將一個簡單的函數應用於流元素,你可以使用fmap :
fmap (B.map toUpper) . readFile
為了您的方便,它也是一個系列的教師。
最有趣的功能是這是一系列替代函子。 這允許您路由流並允許多個流處理器在放棄之前“嘗試”。 這可以擴展到一個完整的解析庫,甚至可以使用一些靜態信息進行優化。
您可以使用流處理器實現有限形式的FRP。 例如,使用pipes
庫,您可以定義事件源:
mouseCoordinates :: (Proxy p) => () -> Producer p MouseCoord IO r
...您可以類似地定義一個圖形處理程序,它接受鼠標坐標並更新畫布上的光標:
coordHandler :: (Proxy p) => () -> Consumer p MouseCoord IO r
然后,您將使用組合將鼠標事件連接到處理程序:
>>> runProxy $ mouseCoordinates >-> coordHandler
它會像你期望的那樣運行。
就像你說的那樣,這適用於單個連鎖階段,但是更多的任意拓撲呢? 好吧,事實證明,由於中央Proxy
類型的pipes
是monad變換器,你可以通過在它們自己之上嵌套代理monad變換器來建模任何任意拓撲。 例如,以下是如何壓縮兩個輸入流:
zipD
:: (Monad m, Proxy p1, Proxy p2, Proxy p3)
=> () -> Consumer p1 a (Consumer p2 b (Producer p3 (a, b) m)) r
zipD () = runIdentityP $ hoist (runIdentityP . hoist runIdentityP) $ forever $ do
a <- request () -- Request from the outer Consumer
b <- lift $ request () -- Request from the inner consumer
lift $ lift $ respond (a, b) -- Respond to the Producer
這表現得像一個curried函數。 您可以按順序將其部分應用於每個輸入,然后可以在完全應用它時運行它。
-- 1st application
p1 = runProxyK $ zipD <-< fromListS [1..]
-- 2nd application
p2 = runProxyK $ p2 <-< fromListS [4..6]
-- 3rd application
p3 = runProxy $ printD <-< p3
它以您期望的方式運行:
>>> p3
(1, 4)
(2, 5)
(3, 6)
這個技巧推廣到任何拓撲。 您可以在“分支,拉鏈和合並”部分的Control.Proxy.Tutorial中找到有關此內容的更多詳細信息。 特別是,您應該檢查它使用的fork
組合器作為示例,它允許您將流拆分為兩個輸出。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.