[Haskell-cafe] Sending messages up-and-down the iteratee-enumerator chain [Was: iterIO-0.1]
oleg at okmij.org
oleg at okmij.org
Sat May 14 13:57:29 CEST 2011
Sorry, this is just a simple answer to one question:
> However, I still have two questions. First, the Iter type in your
> message seems more like your first iteratee implementation, which is
> the approach iterIO and enumerator now take. I wonder if it's
> possible to implement something like Tell your current, CPS-based
> iteratee. Part of the reason I didn't take a CPS-based approach for
> Iter was that I couldn't get the upward control requests to work.
> (Also I wanted pure iteratees, which reduced the gain from CPS.)
Here are the differences from the file UpDown.hs (along the lines of
IterateeMCPS.hs)
newtype IterCPS ee ie a = -- non-monadic answer-type
IterCPS{runIter :: forall r.
(a -> r) ->
((Stream ie -> IterCPS ee ie a) -> r) ->
(ee (IterCPS ee ie) a -> r) ->
r}
instance Bindable ee => Monad (IterCPS ee ie) where
return x = IterCPS $ \ kd _ _ -> kd x
IterCPS m >>= f = IterCPS $ \kd kc ke ->
let m_done x = runIter (f x) kd kc ke
m_cont g = kc (\s -> g s >>= f)
m_iexc e = ke (comp e f)
in m m_done m_cont m_iexc
-- The simplest iteratee, which doesn't do anything but asks for trouble
ierr :: Sum2 Err c => IterCPS c ie a
ierr = IterCPS $ \_ _ ke -> ke . inj2 $ Err (\_ -> ierr)
-- A small iteratee: asks for little and accepts little
-- Return the current element
iehead :: (Sum2 Err c, Bindable c) => IterCPS c EOF Char
iehead = IterCPS $ \_ kc _ -> kc step
where
step (Chunk a) = return a
step (SExc EOF) = ierr
-- Ask for the current position
itell :: (Sum2 Tell c, Bindable c) => IterCPS c ie Int
itell = IterCPS $ \_ _ ke -> ke . inj2 $ Tell return
-- check to see if the current character is 'a' and it occurs at pos 2 (1-based)
ietell :: (Sum2 Err c, Sum2 Tell c, Bindable c) => IterCPS c EOF Bool
ietell = IterCPS $ \_ kc _ -> kc step
where
step (Chunk 'a') = itell >>= return . (== 2)
step (Chunk _) = return False
step (SExc EOF) = ierr
-- Like iehead, but accept the Flush message
ieflush :: (Sum2 Err c, Bindable c) => IterCPS c (Either EOF Flush) Char
ieflush = IterCPS $ \_ kc _ -> kc step
where
step (Chunk a) = return a
step (SExc x) | Just EOF <- prj x = ierr
step (SExc x) | Just Flush <- prj x = ieflush
-- Enumerators and enumeratees
-- Enumerators, in contrast, are explicit in what requests they may
-- satisfy, but implicit in what they may send on the stream.
-- Simple typical enumerator
-- The iteratee must at least accept EOF
-- The iteratee may return Err, but no other requests
en_str :: Sum EOF ie => String -> IterCPS Err ie x -> IterCPS Err ie x
en_str str i = runIter i kd kc ke
where
kd = return
kc k = case str of
"" -> k eof
(h:t) -> en_str t $ k (Chunk h)
ke x | Just (Err _) <- prj2 x = ierr
-- A typical enumeratee
-- It keeps the track of positions
-- It is explicit in requests it accepts: only Tell and Err.
-- It is polymorphic in the in-stream messages
en_pos :: Int -> IterCPS (E2 Err Tell) ie x -> IterCPS Err ie x
en_pos n i = runIter i kd kc ke
where
kd = return
kc k = IterCPS $ \_ kc _ -> kc (\s -> en_pos (n+1) (k s))
ke x | Just (Err _) <- prj2 x = ierr
ke x | Just (Tell k) <- prj2 x = en_pos n (k n)
irun :: Sum EOF ie => IterCPS Err ie x -> x
irun i = runIter i kd kc ke
where
kd x = x
kc k = irun $ k eof
ke _ = error "Iter error"
The rest of the code, including the tests, are the same.
More information about the Haskell-Cafe
mailing list