Skip to content

Commit 369c543

Browse files
committed
Some monad stack simplifications
1 parent f3cf912 commit 369c543

File tree

4 files changed

+55
-57
lines changed

4 files changed

+55
-57
lines changed

examples/test.purs.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import Text.Parsing.Parser.String
1515
parens :: forall m a. (Monad m) => ParserT String m a -> ParserT String m a
1616
parens = between (string "(") (string ")")
1717

18-
nested :: forall m. (Monad m) => ParserT String m Number
18+
nested :: forall m. (Functor m, Monad m) => ParserT String m Number
1919
nested = fix $ \p -> (do
2020
string "a"
2121
return 0) <|> ((+) 1) <$> parens p

src/Text/Parsing/Parser.purs.hs

+29-23
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Prelude
55
import Data.Either
66
import Data.Maybe
77
import Data.Monoid
8+
import Data.Tuple
89

910
import Control.Monad
1011
import Control.Monad.Identity
@@ -24,55 +25,60 @@ instance errorParseError :: Error ParseError where
2425
noMsg = ParseError { message: "" }
2526
strMsg msg = ParseError { message: msg }
2627

27-
data Consumed = Consumed Boolean
28+
data ParserT s m a = ParserT (s -> m { input :: s, result :: Either ParseError a, consumed :: Boolean })
2829

29-
runConsumed :: Consumed -> Boolean
30-
runConsumed (Consumed c) = c
31-
32-
data ParserT s m a = ParserT (StateT s (StateT Consumed (ErrorT ParseError m)) a)
33-
34-
unParserT :: forall m s a. ParserT s m a -> StateT s (StateT Consumed (ErrorT ParseError m)) a
30+
unParserT :: forall m s a. ParserT s m a -> s -> m { input :: s, result :: Either ParseError a, consumed :: Boolean }
3531
unParserT (ParserT p) = p
3632

3733
runParserT :: forall m s a. (Monad m) => s -> ParserT s m a -> m (Either ParseError a)
38-
runParserT s = runErrorT <<< flip evalStateT (Consumed false) <<< flip evalStateT s <<< unParserT
34+
runParserT s p = do
35+
o <- unParserT p s
36+
return o.result
3937

4038
type Parser s a = ParserT s Identity a
4139

4240
runParser :: forall s a. s -> Parser s a -> Either ParseError a
4341
runParser s = runIdentity <<< runParserT s
4442

45-
instance functorParserT :: (Monad m) => Functor (ParserT s m) where
46-
(<$>) = liftA1
43+
instance functorParserT :: (Functor m) => Functor (ParserT s m) where
44+
(<$>) f p = ParserT $ \s -> f' <$> unParserT p s
45+
where
46+
f' o = { input: o.input, result: f <$> o.result, consumed: o.consumed }
4747

4848
instance applyParserT :: (Monad m) => Apply (ParserT s m) where
4949
(<*>) = ap
5050

5151
instance applicativeParserT :: (Monad m) => Applicative (ParserT s m) where
52-
pure a = ParserT (pure a)
52+
pure a = ParserT $ \s -> pure { input: s, result: Right a, consumed: false }
5353

5454
instance alternativeParserT :: (Monad m) => Alternative (ParserT s m) where
55-
empty = ParserT empty
56-
(<|>) p1 p2 = ParserT (unParserT p1 <|> unParserT p2)
55+
empty = fail "No alternative"
56+
(<|>) p1 p2 = ParserT $ \s -> unParserT p1 s >>= \o ->
57+
case o.result of
58+
Left _ | not o.consumed -> unParserT p2 s
59+
_ -> return o
5760

5861
instance bindParserT :: (Monad m) => Bind (ParserT s m) where
59-
(>>=) p f = ParserT (unParserT p >>= (unParserT <<< f))
62+
(>>=) p f = ParserT $ \s -> unParserT p s >>= \o ->
63+
case o.result of
64+
Left err -> return { input: o.input, result: Left err, consumed: o.consumed }
65+
Right a -> updateConsumedFlag o.consumed <$> unParserT (f a) o.input
66+
where
67+
updateConsumedFlag c o = { input: o.input, consumed: c || o.consumed, result: o.result }
6068

6169
instance monadParserT :: (Monad m) => Monad (ParserT s m)
6270

6371
instance monadTransParserT :: MonadTrans (ParserT s) where
64-
lift m = ParserT (lift (lift (lift m)))
65-
66-
instance monadErrorParserT :: (Monad m) => MonadError ParseError (ParserT s m) where
67-
throwError e = ParserT (throwError e)
68-
catchError p f = ParserT (catchError (unParserT p) (unParserT <<< f))
72+
lift m = ParserT $ \s -> (\a -> { input: s, consumed: false, result: Right a }) <$> m
6973

7074
instance monadStateParserT :: (Monad m) => MonadState s (ParserT s m) where
71-
state f = ParserT (state f)
75+
state f = ParserT $ \s ->
76+
return $ case f s of
77+
Tuple a s' -> { input: s', consumed: false, result: Right a }
7278

73-
instance monadStateConsumerParserT :: (Monad m) => MonadState Consumed (ParserT s m) where
74-
state f = ParserT (state f)
79+
consume :: forall s m. (Monad m) => ParserT s m {}
80+
consume = ParserT $ \s -> return { consumed: true, input: s, result: Right {} }
7581

7682
fail :: forall m s a. (Monad m) => String -> ParserT s m a
77-
fail message = throwError (ParseError { message: message })
83+
fail message = ParserT $ \s -> return { input: s, consumed: false, result: Left (ParseError { message: message }) }
7884

src/Text/Parsing/Parser/Combinators.purs.hs

+9-9
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ import Control.Monad.State.Class
1717
import Text.Parsing.Parser
1818

1919
fix :: forall m s a. (ParserT m s a -> ParserT m s a) -> ParserT m s a
20-
fix f = ParserT (StateT (\s -> runStateT (unParserT (f (fix f))) s))
20+
fix f = ParserT $ \s -> unParserT (f (fix f)) s
2121

2222
fix2 :: forall m s a b. (Tuple (ParserT m s a) (ParserT m s b) -> Tuple (ParserT m s a) (ParserT m s b)) -> Tuple (ParserT m s a) (ParserT m s b)
2323
fix2 f = Tuple
24-
(ParserT (StateT (\s -> runStateT (unParserT (fst (f (fix2 f)))) s)))
25-
(ParserT (StateT (\s -> runStateT (unParserT (snd (f (fix2 f)))) s)))
24+
(ParserT $ \s -> unParserT (fst (f (fix2 f))) s)
25+
(ParserT $ \s -> unParserT (snd (f (fix2 f))) s)
2626

2727
many :: forall m s a. (Monad m) => ParserT s m a -> ParserT s m [a]
2828
many p = many1 p <|> return []
@@ -49,14 +49,14 @@ optional :: forall m s a. (Monad m) => ParserT s m a -> ParserT s m {}
4949
optional p = (do p
5050
return {}) <|> return {}
5151

52-
optionMaybe :: forall m s a. (Monad m) => ParserT s m a -> ParserT s m (Maybe a)
52+
optionMaybe :: forall m s a. (Functor m, Monad m) => ParserT s m a -> ParserT s m (Maybe a)
5353
optionMaybe p = option Nothing (Just <$> p)
5454

55-
try :: forall m s a. (Monad m) => ParserT s m a -> ParserT s m a
56-
try p = catchError p $ \e -> do
57-
Consumed consumed <- get
58-
when consumed $ put (Consumed false)
59-
throwError (e :: ParseError)
55+
try :: forall m s a. (Functor m) => ParserT s m a -> ParserT s m a
56+
try p = ParserT $ \s -> try' s <$> unParserT p s
57+
where
58+
try' s o@{ result = Left _ } = { input: s, result: o.result, consumed: false }
59+
try' _ o = o
6060

6161
sepBy :: forall m s a sep. (Monad m) => ParserT s m a -> ParserT s m sep -> ParserT s m [a]
6262
sepBy p sep = sepBy1 p sep <|> return []

src/Text/Parsing/Parser/String.purs.hs

+16-24
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ module Text.Parsing.Parser.String where
33
import Prelude
44

55
import Data.String
6+
import Data.Either
67

7-
import Control.Monad.State.Class
8+
import Control.Monad.Error
89
import Control.Monad.Error.Class
10+
import Control.Monad.State.Class
911

1012
import Data.Foldable
1113
import Data.Monoid
@@ -14,37 +16,27 @@ import Text.Parsing.Parser
1416
import Text.Parsing.Parser.Combinators
1517

1618
eof :: forall m. (Monad m) => ParserT String m {}
17-
eof = do
18-
s <- get
19-
case s of
20-
"" -> return {}
21-
_ -> fail "Expected EOF"
19+
eof = ParserT $ \s ->
20+
return $ case s of
21+
"" -> { consumed: false, input: s, result: Right {} }
22+
_ -> { consumed: false, input: s, result: Left (strMsg "Expected EOF") }
2223

2324
string :: forall m. (Monad m) => String -> ParserT String m String
24-
string s = do
25-
s' <- get
26-
case indexOf s s' of
27-
0 -> do
28-
put (Consumed true)
29-
put (drop (length s) s')
30-
return s
31-
_ -> fail $ "Expected \"" ++ s ++ "\""
25+
string s = ParserT $ \s' ->
26+
return $ case indexOf s s' of
27+
0 -> { consumed: true, input: drop (length s) s', result: Right s }
28+
_ -> { consumed: false, input: s', result: Left (strMsg ("Expected " ++ show s)) }
3229

3330
char :: forall m. (Monad m) => ParserT String m String
34-
char = do
35-
s <- get
36-
case s of
37-
"" -> fail "Unexpected EOF"
38-
_ -> do
39-
put (Consumed true)
40-
put (drop 1 s)
41-
return (take 1 s)
31+
char = ParserT $ \s' ->
32+
return $ case s' of
33+
"" -> { consumed: false, input: s', result: Left (strMsg "Unexpected EOF") }
34+
_ -> { consumed: true, input: drop 1 s', result: Right (charAt 0 s') }
4235

4336
satisfy :: forall m. (Monad m) => (String -> Boolean) -> ParserT String m String
4437
satisfy f = do
4538
p <- char
46-
r <- if not $ f p then fail "Character did not satisfy prediate" else return p
47-
return r
39+
if f p then return p else fail "Character did not satisfy predicate"
4840

4941
whiteSpace :: forall m. (Monad m) => ParserT String m String
5042
whiteSpace = do

0 commit comments

Comments
 (0)