【问题标题】:examples in the paper Monadic Parse in HaskellHaskell 中的 Monadic Parse 论文中的示例
【发布时间】:2017-03-29 11:06:58
【问题描述】:

在论文Monadic Parse in Haskell中,作者给出了一个解析简单算术字符串的例子。我尝试扩展term,将其应用于"1 + 2",但我仍然对解析器的递归性质感到困惑。也就是term如果我做对了会展开成下面的形式

expr = ((digit +++ do {symb "("; n <- expr; symb ")"; return n}) 
           `chianl1` mulop) `chainl1` addop

但是在第一次用digit解析了字符串"1 + 2"中的数字"1"addop解析了"+"之后,为什么解析器expr会继续解析"2"后面的数字呢?

此外,当我将term 应用到"1 - 2 * 3 + 4"(这是论文中给出的示例)时,我得到的是[(-5,"+ 4")] 而不是[(-1, "")]。是我的代码的问题吗?然而,我已经根据论文中的代码检查了我的代码,并没有发现任何偏差。

下面是我的代码

module Parser where 

import Prelude hiding (filter)
import Data.Char (isDigit, isSpace, toUpper, ord)

newtype Parser a = Parser {
runParser :: (String -> [(a, String)])
}

instance Monad Parser where 
    return a = Parser $ \s -> [(a, s)]
    p >>= f = Parser $ \s ->
        concat [runParser (f a) s' | (a, s') <- runParser p s]

instance Applicative Parser where 
    pure a = Parser $ \s -> [(a, s)] 
    k <*> m = Parser $ \s -> 
         [(f a, s'') |
           (f, s') <- runParser k s,
           (a, s'') <- runParser m s']

instance Functor Parser where 
   fmap f p = Parser $ \s -> 
            [(f a, s')  | (a, s') <- runParser p s]

applyP :: Parser a -> String -> [(a, String)]
applyP p s = runParser p s

emptyP :: Parser a
emptyP = Parser $ \s -> [] 

appendP :: Parser a-> Parser a-> Parser a 
appendP p q = Parser $ \s -> 
   let xs = runParser p s 
       ys = runParser q s 
    in xs ++ ys

(+++) :: Parser a -> Parser a -> Parser a
p +++ q = Parser $ \s -> 
        case (runParser (p `appendP` q) s) of 
        []     -> []
        (x:xs) -> return x

item :: Parser Char 
item = Parser $ \cs -> 
        case cs of 
            []     -> [] 
            (c:cs) -> [(c, cs)]         

-- since the function tiem is of type "Parser Char"
-- it can only produce char as a result of computation
filterP :: (Char -> Bool) -> Parser Char
filterP f = item >>= \c -> if f c 
          then return c 
          else emptyP 

-- returns ak result if the prefix char matches
char :: Char -> Parser Char 
char c = filterP (\x -> x == c)

-- parses a specific string 
string :: String -> Parser String
string [] = return ""  -- why it will be an empty list if "emptyP" is used? 
string (x:xs) = do c <- char x
                   cs <- string xs 
                   return (c:cs)

many :: Parser a -> Parser [a]
many p = many1 p +++  (return []) 

many1 :: Parser a -> Parser [a]
many1 p = do c <- p 
             cs <- many p 
         return (c:cs)

sepby :: Parser a -> Parser b -> Parser [a] 
sepby p sep = sepby1 p sep +++ (return [])

sepby1 :: Parser a -> Parser b -> Parser [a] 
sepby1 p sep = do c <- p 
                  cs <- many (sep >> p)
               return (c:cs)

chainl :: Parser a -> Parser (a -> a -> a) -> a -> Parser a 
chainl p q a = (p `chainl1` q) +++ return a 

chainl1 :: Parser a -> Parser (a -> a -> a) -> Parser a 
p `chainl1` q = do {a <- p; rest a} 
            where rest a = (do  f <- q
                                b <- p
                            return (f a b))
                           +++ return a 

space :: Parser String 
space = many (filterP isSpace)  

-- parse a given value, throw away trailing space
token :: Parser a -> Parser a 
token p = do {a <- p; space; return a} 

-- parses a given token, throws away trailing space
symb :: String -> Parser String 
symb s = token (string s)

-- throw away any prefix space, apply parser 
apply :: Parser a -> String -> [(a, String)]
apply p = runParser (do {space; p})

addop :: Parser (Int -> Int -> Int) 
addop = do {symb "+"; return (+)} +++ do {symb "-"; return (-)}

mulop :: Parser (Int -> Int -> Int)
mulop = do {symb "*"; return (*)} +++ do {symb "/"; return (div)}

digit = do {x <- token (filterP isDigit); return (ord x - ord '0')}
factor = digit +++ do {symb "("; n <- expr; symb ")"; return n}
term = factor `chainl1` mulop
expr = term `chainl1` addop

非常感谢!!

【问题讨论】:

  • 是不是就像这里定义的函数实际上是论文“如何用成功列表替换失败”中不同语法的函数?我正在阅读那篇论文,并意识到两者之间的巨大相似之处。

标签: parsing haskell monads


【解决方案1】:

chainl1 中,您将对rest 的递归调用替换为return

rest a = do f <- q
            b <- p
            rest (f a b)
         +++ return a

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-05
    • 2013-06-04
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 2012-02-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多