Hi,
I'm wondering if it's possible to use a pipes-like stream to express "contextual" filtering of elements. For example, taking a simplistic view of a block comment as a groups lines such that the first line that begins with "{-" and the last line begins with "-}", I'd like to be able to filter a stream like:
[ "foo"
, "{- hi"
, "there -}"
, "bar"
, "{- whoops"
]into
[ "foo", "bar"
]
Using the streaming library (similar to pipes + pipes-group + pipes-parse), my first attempt was something like:
import Streaming
import qualified Streaming.Prelude as S
filterBlockComments :: forall m r. Stream (Of String) m r -> Stream (Of String) m r
filterBlockComments s0 = do
-- s0 == ["foo", "{- hi", "there -}", "bar", "{- whoops"]
-- yield ["foo"], leaving
-- s1 == ["{- hi", "there -}", "bar", "{- whoops"]
s1 :: Stream (Of String) m r
<- S.span (\line -> not ("{-" `isPrefixOf` line)) s0
-- break s1 into (["{- hi"], ["there -}", "bar", "{- whoops"]),
-- then drop the first element of the second half, leaving
-- (["{- hi"], ["bar", "{- whoops"])
let s2 :: Stream (Of String) m (Stream (Of String) m r)
s2 = fmap (S.drop 1) (S.break (\line -> "-}" `isSuffixOf` line) s1)
-- run s2 without yielding its elements, leaving
-- s3 == ["bar", "{- whoops"]
s3 <- lift (S.effects s2)
-- loop
filterBlockComments s3
However, this doesn't terminate, for reasons I haven't quite figured out other than I'm doing streaming "wrong". So, is there a more idiomatic way to write such a function?
Thanks,
Mitchell