I am following the following paper and struggling to implement. The code does not mention the implementation of parse or ord. I tried to do it without implementing Prelude, but this is my next exercise, hence the comment at the top.
My code is as follows, copying directly from the Paper:
{- {-# LANGUAGE NoImplicitPrelude #-}
type String :: *
type String = [ Char ]
type Char :: *
data Char = GHC.Types.C# GHC.Prim.Char#
-}
newtype Parser a = Parser (String -> [(a,String)])
item :: Parser Char
item = Parser (\cs -> case cs of
"" -> []
(c:cs) -> [(c,cs)])
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
instance Main.Monad Parser where
return a = Parser (\cs -> [(a,cs)])
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
p >>= f = Parser (\cs -> concat [parse (f a) cs' |
(a,cs') <- parse p cs])
p :: Parser (Char,Char)
p = do {c <- item; item; d <- item; Main.return (c,d)}
class Main.Monad m => MonadZero m where
zero :: m a
class MonadZero m => MonadPlus m where
(++) :: m a -> m a -> m a
instance MonadZero Parser where
zero :: Parser a
zero = Parser (\cs -> [])
instance MonadPlus Parser where
p ++ q = Parser (\cs -> parse p cs Main.++ parse q cs)
(+++) :: Parser a -> Parser a -> Parser a
p +++ q = Parser (\cs -> case parse (p Main.++ q) cs of
[] -> []
(x:xs) -> [x])
sat :: (Char -> Bool) -> Parser Char
sat p = do {c <- item; if p c then Main.return c else zero}
char :: Char -> Parser Char
char c = sat (c ==)
string :: String -> Parser String
string "" = Main.return ""
string (c:cs) = do {char c; string cs; Main.return (c:cs)}
many :: Parser a -> Parser [a]
many p = many1 p +++ Main.return []
many1 :: Parser a -> Parser [a]
many1 p = do {a <- p; as <- many p; Main.return (a:as)}
sepby :: Parser a -> Parser b -> Parser [a]
p `sepby` sep = (p `sepby1` sep) +++ Main.return []
sepby1 :: Parser a -> Parser b -> Parser [a]
p `sepby1` sep = do a <-p
as <- many (do {sep; p})
Main.return (a:as)
chainl :: Parser a -> Parser (a -> a -> a) -> a -> Parser a
chainl p op a = (p `chainl1` op) +++ Main.return a
chainl1 :: Parser a -> Parser (a -> a -> a) -> Parser a
p `chainl1` op = do {a <- p; rest a}
where
rest a = (do f <- op
b <- p
rest (f a b))
+++ Main.return a
space :: Parser String
space = many (sat isSpace)
token :: Parser a -> Parser a
token p = do {a <- p; space; Main.return a}
symb :: String -> Parser String
symb cs = token (string cs)
apply :: Parser a -> String -> [(a,String)]
apply p = parse (do {space; p})
expr :: Parser Int
addop :: Parser (Int -> Int -> Int)
mulop :: Parser (Int -> Int -> Int)
expr = term `chainl1` addop
term = factor `chainl1` mulop
factor = digit +++ do {symb "("; n <- expr; symb ")"; Main.return n}
digit = do {x <- token (sat isDigit); Main.return (ord x - ord '0')}
addop = do {symb "+"; Main.return (+)} +++ do {symb "-"; Main.return (-)}
mulop = do {symb "*"; Main.return (*)} +++ do {symb "/"; Main.return (div)}
The problem is that the parse function is not defined anywhere, and when trying to compile using GHCi, I get the following error:
GHCi, version 9.4.8: https://www.haskell.org/ghc/ :? for help
[1 of 2] Compiling Main ( MonadicParsingInHaskell.hs, interpreted )
MonadicParsingInHaskell.hs:24:41: error:
Variable not in scope: parse :: Parser b -> t0 -> [(b, String)]
|
24 | p >>= f = Parser (\cs -> concat [parse (f a) cs' |
| ^^^^^
MonadicParsingInHaskell.hs:25:47: error:
Variable not in scope: parse :: Parser a -> String -> [(a, t0)]
|
25 | (a,cs') <- parse p cs])
| ^^^^^
MonadicParsingInHaskell.hs:41:31: error:
Variable not in scope: parse :: Parser a -> String -> [(a, String)]
|
41 | p ++ q = Parser (\cs -> parse p cs Main.++ parse q cs)
| ^^^^^
MonadicParsingInHaskell.hs:41:50: error:
Variable not in scope: parse :: Parser a -> String -> [(a, String)]
|
41 | p ++ q = Parser (\cs -> parse p cs Main.++ parse q cs)
| ^^^^^
MonadicParsingInHaskell.hs:44:31: error:
Variable not in scope: parse :: Parser a -> String -> [(a, String)]
|
44 | p +++ q = Parser (\cs -> case parse (p Main.++ q) cs of
| ^^^^^
MonadicParsingInHaskell.hs:84:19: error:
Variable not in scope: isSpace :: Char -> Bool
Suggested fix: Perhaps use ‘space’ (line 84)
|
84 | space = many (sat isSpace)
| ^^^^^^^
MonadicParsingInHaskell.hs:93:11: error:
Variable not in scope: parse :: Parser a -> String -> [(a, String)]
|
93 | apply p = parse (do {space; p})
| ^^^^^
MonadicParsingInHaskell.hs:102:29: error:
Variable not in scope: isDigit :: Char -> Bool
|
102 | digit = do {x <- token (sat isDigit); Main.return (ord x - ord '0')}
| ^^^^^^^
MonadicParsingInHaskell.hs:102:52: error:
Variable not in scope: ord :: Char -> b
Suggested fix:
Perhaps use one of these:
‘or’ (imported from Prelude), ‘odd’ (imported from Prelude)
|
102 | digit = do {x <- token (sat isDigit); Main.return (ord x - ord '0')}
| ^^^
MonadicParsingInHaskell.hs:102:60: error:
Variable not in scope: ord :: Char -> b
Suggested fix:
Perhaps use one of these:
‘or’ (imported from Prelude), ‘odd’ (imported from Prelude)
|
102 | digit = do {x <- token (sat isDigit); Main.return (ord x - ord '0')}
| ^^^
Failed, no modules loaded.
I have tried to get the code from the paper to compile but had no luck. I think I need to define the parse and ord functions myself, but I'm not sure if I am have just implemented the code incorrectly -- I am almost certain I haven't.
parseis in fact defined in the paper on page 438. It's also guessable from the type signature GHC tells you it should have.ordandisSpaceare inData.Char.Other notes: Please avoid reimplementing language primitives (like
Char) in real code. By convention, anything with a#in its name is to be considered "low-level" and an implementation detail, can't even be named without theMagicHashextension, and should not be touched in >90% of cases.NoImplicitPreludeis not useful except in the very rare case that you want to avoid importing instances fromPrelude. Otherwise a simple (and standard!)import Prelude()causes all names fromPreludeto be out of scope. You add individual names to the import list instead of reimplementing stuff that you really shouldn't. Also,*as a kind is obsolete and should be replaced withData.Kind.Type