suztomoの日記

To be a good software engineer

I'm trying to understand Iteratee section in [themonadreader.files.wordpress.com/2010/05/issue16.pdf:title=Monad Reader 16].

alternates :: IterV el [el]
alternates = fmap catMaybes . sequence . replicate 5 $ drop1keep1

-- replicate 5 $drop1keep1               :: [IterV el (Maybe el)]
-- sequence . replicate 5 $ drop1keep1   :: IterV el [ Maybe el ]                 Let's say this as X
-- fmap catMaybes X                      :: IterV el (([Maybe a] -> [a]) [ Maybe el ])
-- fmap catMaybes X                      :: IterV el [ el ]

Type notation

Suppose we have a type "V X Y Z", this should be understood as "(V X Y) Z". If V X Y is monad, the type has value Z.

z <- vxyz :: V X Y Z
z

The type of z is Z. And return always wrap a value with appropriate "context" (Monadic type) like:

somefunc :: V X Y Z
somefunc = do
    return z

Here, without specifying V X Y, "return" generates Monadic value of type "V X Y Z"

Iteratee with IO

Around p.27 of Monad.Reader#16.

type EnumeratorM el m a = IterV el a -> m (IterV el a)

enumHandle :: Handle -> EnumeratorM Char IO a
--                      IterV Char a -> m (IterV Char a)
enumHandle h iter = loop iter where
    loop :: IterV Char a -> IO (IterV Char a)
    loop i@(Done _ _) = return i
    loop i@(Cont k) = do
      isEOF <- hIsEOF h
      if isEOF
      then return i
      else do
        e <- hGetChar h
        loop . k . El $ e
--             k :: (StreamG Char -> IterV Char a)


enumFile :: FilePath -> EnumeratorM Char IO a
--                      IterV Char a -> m (IterV Char a)
enumFile fp i = bracket
                   (openFile fp ReadMode)
                   (hClose)
                   (flip enumHandle i)
                   
lengthOfTwoFiles :: FilePath -> FilePath -> IO (Maybe Int)
lengthOfTwoFiles fp1 fp2 =
    fmap run $ ((enumFile fp1) >=> (enumFile fp2)) length
-- enumFile fp1 :: IterV Char a -> IO (IterV Char a) -> x -> m x
-- enumFile fp2 :: IterV Char a -> IO (IterV Char a) -> x -> m x
-- length :: IterV el Int                           -> x
-- (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c

The last fmap works over "IO (IterV Char Int)", the right side of "$"

Evaluate iteratee: length

As I'm not clear about how iteratees work, here I write down the step of "length" iteratee.

length :: IterV el Int
length = Cont (step 0)
  where
    step acc (El _) = Cont (step (acc+1))
    step acc Empty = Cont (step acc)
    step acc EOF = Done acc EOF


enum :: IterV el a -> [el] -> IterV el a
enum i [] = i
enum i@(Done _ _) _ = i
enum (Cont k) (x:xs) = enum (k (El x)) xs

run :: IterV el a -> Maybe a
run (Done x _) = Just x
run (Cont k) = run' (k EOF)
 where
   run' (Done x _) = Just x
   run' _ = Nothing
*Main> run $ enum length "abc"
Just 3
-- as the first operation of run is pattern match, we have to evaluate the arguments
run $ enum length "abc"

-- as the first operation of enum is pattern match, we have to evaluate the arguments
run $ enum (Cont (step 0)) "abc"

-- Using the last equation of enum
run $ enum ((step 0) El 'a') "bc"

-- as the first operation of enum is pattern match, evaluate the first argument
-- Here, it discards the 'a'. Using the first rule of step.
run $enum (Cont (step (0+1))) "bc"

-- Continues...
run $ enum (step (0+1) (El 'b')) "c"  -- Using the last rule of enum

run $ enum (Cont (step (0+1+1))) "c" -- definition of step as we need pattern match for the first argument

run $ enum (step (0+1+1) (El 'c')) [] -- Using the last rule of enum
run $ enum (step (0+1+1) (El 'c')) [] -- Using the last rule of enum

run $ step (0+1+1) (El 'c') -- Using the first rule of enum. As we need pattern match against the first argument of run, we continue evaluate the right side of '$'

run $ Cont (step (0+1+1+1))   -- Using first rule of step

run' (step (0+1+1+1) EOF)    -- Using second rule of run

run' (Done (0+1+1+1) EOF)    -- The first argument of run' needs to be evaluated

Just (0+1+1+1) -- using the first rule of run'

Just 3 -- evaluate to output the result