2013-03-06 36 views
13

我想了解管道管道之間的差異。不像,導管有剩飯的概念。什麼是剩菜有用?我希望看到一些例子,其中剩菜是必不可少的。管道的剩菜有什麼好處?

而且由於管道沒有剩菜的概念,有沒有什麼方法可以實現與他們類似的行爲?

回答

17

加布裏埃爾指出,剩菜總是解析的一部分是有趣的。我不確定我會同意,但這可能僅取決於解析的定義。

有一大類需要剩菜的用例。解析當然是一種解析:任何時候解析都需要某種預測,你需要剩菜。其中一個例子是降價包的getIndented函數,該函數將所有即將到來的行與一定的縮進級別隔離開,剩下的行將在稍後處理。

但是一個更普通的例子集中在管道本身。每當你處理打包數據(比如ByteString或Text)時,你都需要閱讀一個塊,以某種方式分析它,使用剩餘的來推回額外的內容,然後對原始內容進行一些處理。也許這個最簡單的例子是dropWhile。實際上,我認爲剩下的就是流媒體庫的核心基本特徵,即新的1.0管道接口甚至不會向禁用殘羹剩飯的用戶公開該選項。我知道很少有真實世界的用例不需要以這種或那種方式。

+0

感謝您的解釋,我現在很確信。與此同時,我正在考慮如何在類似導管的庫的基礎上實施剩菜,這種庫本來就沒有。這個想法是,一個帶剩飯的管道可以表示爲一個返回'(也許我,r)'的渠道。我的嘗試(對於管道)是[這裏](https://gist.github.com/ppetr/5110909)。 – 2013-03-07 19:37:37

+0

我認爲你有正確的直覺,你的實現與內部的工作方式非常相似。我認爲你發現了剩餘的雙邊問題,這就是爲什麼剩菜可以作爲多個剩餘的建設者堆放在管道中。 – 2013-03-08 05:40:24

+0

剩下的[另一個嘗試](https://gist.github.com/ppetr/5110909#file-feedback-hs)(我很可能會用在我的Scala庫中)用於剩菜剩飯是將剩菜視爲一種反饋:對於Pipe Void i(io)umr',我們使用內部方法將任何「Left i」發送回其輸入,將內部管道轉換爲標準管道。 – 2013-03-13 13:12:07

15

我會回答pipes。你的問題的簡短答案是即將推出的pipes-parse庫將作爲更一般的解析框架的一部分支持剩菜。我發現幾乎每個人都想要剩菜的情況下,他們實際上需要一個解析器,這就是爲什麼我將剩菜剩餘問題作爲解析子集的原因。你可以找到目前的圖書館草稿here

但是,如果您想了解pipes-parse如何使其運行,實現剩餘物的最簡單方法是僅使用StateP來存儲推回緩衝區。這僅需要定義以下兩個功能:

import Control.Proxy 
import Control.Proxy.Trans.State 

draw :: (Monad m, Proxy p) => StateP [a] p() a b' b m a 
draw = do 
    s <- get 
    case s of 
     [] -> request() 
     a:as -> do 
      put as 
      return a 

unDraw :: (Monad m, Proxy p) => a -> StateP [a] p() a b' b m() 
unDraw a = do 
    as <- get 
    put (a:as) 

draw首先查閱推回緩衝區,以查看是否有任何所存儲的元素,彈出一個元件從堆棧如果有的話。如果緩衝區爲空,它將從上游請求一個新元素。當然,如果我們不能推回任何東西,那麼沒有必要使用緩衝區,所以我們還定義了unDraw以將元素推入堆棧以供稍後保存。

編輯:哎呀,我忘了包括一個有用的例子,當剩菜有用。像邁克爾說的,takeWhiledropWhile是有用的剩菜剩飯。這裏的drawWhile功能(類似於邁克爾·調用takeWhile):

drawWhile :: (Monad m, Proxy p) => (a -> Bool) -> StateP [a] p() a b' b m [a] 
drawWhile pred = go 
    where 
    go = do 
     a <- draw 
     if pred a 
     then do 
      as <- go 
      return (a:as) 
     else do 
      unDraw a 
      return [] 

現在想象一下,你的製作人:

producer() = do 
    respond 1 
    respond 3 
    respond 4 
    respond 6 

...你上癮,最多到使用的消費者:

consumer() = do 
    evens <- drawWhile odd 
    odds <- drawWhile even 

如果第一個drawWhile odd沒有推回它繪製的最後一個元素,那麼你會放棄4,這將不會得到正確傳遞到第二個drawWhile even聲明`。