Я отвечу за pipes
. Короткий ответ на ваш вопрос заключается в том, что будущая библиотека pipes-parse
будет поддерживать остатки как часть более общей структуры синтаксического анализа. Я обнаружил, что почти в каждом случае, когда людям нужны остатки, им действительно нужен синтаксический анализатор, поэтому я формулирую проблему остатков как подмножество синтаксического анализа. Вы можете найти текущий проект библиотеки здесь.
Однако, если вы хотите понять, как 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
для помещения элемента в стек для сохранения на потом.
Редактировать: Ой, я забыл включить полезный пример того, когда остатки полезны. Как говорит Майкл, takeWhile
и dropWhile
— полезные случаи остатков. Вот функция 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
.
person
Gabriel Gonzalez
schedule
06.03.2013