CatMaybes concatenates maybe values in a list into one list.
*Main> :t catMaybes catMaybes :: [Maybe a] -> [a] *Main> catMaybes [Just "a", Nothing, Nothing, Just "b"] ["a","b"]
CatMaybes concatenates maybe values in a list into one list.
*Main> :t catMaybes catMaybes :: [Maybe a] -> [a] *Main> catMaybes [Just "a", Nothing, Nothing, Just "b"] ["a","b"]
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 ]
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"
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c) f >=> g = \x -> f x >>= g
Once we define ">>=" operator, we can use this left-to-right Kleisli composition using the default implementation.
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 "$"
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