Maintaining a counter
- Two computations modify a counter
Theory and Design of PL (CS 538)
February 26, 2020
itemP :: Parser Char -- parse one of any Char
oneMore :: Char -> Parser (Char, Char)
oneMore c = addC <$> charP c
where addC = \x -> (c, x)
sameTwoP = combiner itemP oneMore
foo :: a -> Maybe b
bar :: b -> Maybe c
baz :: c -> Maybe d
foobarbaz :: a -> Maybe d
foobarbaz x = case foo x of
Nothing -> Nothing
Just y -> case bar y of
Nothing -> Nothing
Just z -> case baz z of
Nothing -> Nothing
Just w -> Just w
foo :: a -> (b, String)
bar :: b -> (c, String)
baz :: c -> (d, String)
foobarbaz :: a -> (c, String)
foobarbaz x = let (y, log1) = foo x in
let (z, log2) = bar y in
let (w, log3) = bar y in
(w, log1 ++ log2 ++ log3)
-- Input: init counter. Output: updated counter + output string
foo :: Int -> (Int, String)
bar :: Int -> (Int, String)
baz :: Int -> (Int, String)
foobarbaz :: Int -> String
foobarbaz c = let (c', out') = foo c in
let (c'', out'') = bar c'' in
let (c''', out''') = bar c''' in
out'''
Maybe a
is either an a
, or nothinginstance Monad Maybe where
-- Given normal value, wrap it with Just
-- return :: a -> Maybe a
return val = Just val
-- Compose two Maybe computations
-- (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
maybe >>= f = case maybe of
Nothing -> Nothing -- First computation failed
Just val -> f val -- First computation OK, run second
WithLog a
is an a
with a String
log
instance Monad WithLog where
-- return :: a -> WithLog a
return val = MkWithLog (val, "")
-- ^-- Empty log
-- (>>=) :: WithLog a -> (a -> WithLog b) -> WithLog b
logA >>= f = let MkWithLog (output, log) = logA in
let MkWithLog (output', log') = f output in
MkWithLog (output', log ++ log')
-- ^--join--^
State s a
is computation that returns an a
instance Monad (State s) where
-- return :: a -> State s a
return val = MkState (\state -> (val, state))
-- ^-- unchanged --^
-- (>>=) :: State s a -> (a -> State s b) -> State s b
(MkState stTrans1) >>= f = MkState $ \st ->
MkState stTrans1 -> let (out', st') = stTrans1 st in
-- ^-Part 1-^
let (MkState stTrans2) = (f out') in stTrans2 st'
-- ^-Part 2-^
foo :: a -> Maybe b
bar :: b -> Maybe c
baz :: c -> Maybe d
foobarbaz :: a -> Maybe d
foobarbaz x = foo x >>= (\y ->
bar y >>= (\z ->
baz z >>= (\w ->
return w)))
>>=
, lambdamonVal >>= (\var -> ...)
into>>=
and return
OrErr a
is either an a
, or an error Stringa
is the “return type”: result of parse-- (>>=) :: Parser a -> (a -> Parser b) -> Parser b
par >>= f = MkParser $ \str ->
let firstRes = runParser par str -- Run parser 1
in case firstRes of -- See what we got...
Nothing -> Nothing -- Parser 1 failed
Just (val, str') -> let par' = f val -- Choose parser 2
in runParser par' str' -- Run parser 2 on rest