Haskell 级联解析器
Cascading Parsers in Haskell
我的解析器类型是
newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
我有两个解析器:
1) a = (satisfy isAlpha)
知道如何匹配字符串中的第一个字母数字字符。
运行 parse a "k345"
给出 Just ('k',"345")
2) b = many (satisfy isDigit)
知道如何匹配任意数量的数字。 运行 parse b "1234 abc"
给出 Just ("1234"," abc")
现在我想组合这两个解析器并匹配后跟任意数字的单个字母数字字符。
我试过了:
parse (a *> b) "k1234 7"
得到 Just ("1234"," 7 ")
。看起来第一个解析器 a
匹配的 'k'
从输出中消失了。我该如何解决这个问题?
谢谢!
看起来工作正常:
parse (fmap (:) (satisfy isAlpha) <*> many (satisfy isDigit)) "k1234 7"
并回馈我想要的
Just ("k1234"," 7")
对于玩具解析器,请查看以下代码:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
module Parse where
import Data.Char
import Data.List
newtype Parser a = Parser
{ parse :: String -> Maybe (a, String) }
satisfy :: (Char -> Bool) -> Parser Char
satisfy cond = Parser $ \s ->
case s of
"" -> Nothing
(c:cs) -> if cond c then Just (c, cs) else Nothing
many :: Parser a -> Parser [a]
many p = Parser $ \s ->
case parse p s of
Nothing -> Just ([], s)
Just (c, cs) -> let Just (cc, cs') = parse (many p) cs
in Just (c:cc, cs')
string :: String -> Parser String
string str = Parser $ \s -> if isPrefixOf str s
then Just (str, drop (length str) s)
else Nothing
instance Functor Parser where
fmap f (Parser g) = Parser $ \s ->
case g s of
Nothing -> Nothing
Just (r, remain) -> Just (f r, remain)
instance Applicative Parser where
pure a = Parser $ \s -> Just (a, s)
-- (<*>) :: f (a -> b) -> f a -> f b
(Parser f) <*> (Parser g) = Parser $ \s ->
case f s of
Nothing -> Nothing
Just (ab, remain) -> case g remain of
Nothing -> Nothing
Just (r, remain1) -> Just (ab r, remain1)
instance Semigroup a => Semigroup (Parser a) where
(Parser p1) <> (Parser p2) = Parser $ \s ->
case p1 s of
Nothing -> Nothing
Just (r1, s1) -> case p2 s1 of
Nothing -> Nothing
Just (r2, s2) -> Just (r1 <> r2, s2)
instance (Monoid a, Semigroup (Parser a))=> Monoid (Parser a) where
mempty = Parser $ \s -> Just (mempty, s)
mappend = (<>)
a = satisfy isAlpha
b = many (satisfy isDigit)
λ> parse a "k345"
Just ('k',"345")
λ> parse b "12345 abc"
Just ("12345"," abc")
λ> parse (a *> b) "k1234 7"
Just ("1234"," 7")
λ> parse (string "k" <> b) "k1234 7"
Just ("k1234"," 7")
所以也许您应该找一些教程并尝试熟悉 Functor
、Applicative
和 Monad
。你看,你可以为你的 Parser
类型实现一个 Monoid
的实例,然后你可以使用 (<>)
将你的解析结果组合在一起。
我的解析器类型是
newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
我有两个解析器:
1) a = (satisfy isAlpha)
知道如何匹配字符串中的第一个字母数字字符。
运行 parse a "k345"
给出 Just ('k',"345")
2) b = many (satisfy isDigit)
知道如何匹配任意数量的数字。 运行 parse b "1234 abc"
给出 Just ("1234"," abc")
现在我想组合这两个解析器并匹配后跟任意数字的单个字母数字字符。
我试过了:
parse (a *> b) "k1234 7"
得到 Just ("1234"," 7 ")
。看起来第一个解析器 a
匹配的 'k'
从输出中消失了。我该如何解决这个问题?
谢谢!
看起来工作正常:
parse (fmap (:) (satisfy isAlpha) <*> many (satisfy isDigit)) "k1234 7"
并回馈我想要的
Just ("k1234"," 7")
对于玩具解析器,请查看以下代码:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
module Parse where
import Data.Char
import Data.List
newtype Parser a = Parser
{ parse :: String -> Maybe (a, String) }
satisfy :: (Char -> Bool) -> Parser Char
satisfy cond = Parser $ \s ->
case s of
"" -> Nothing
(c:cs) -> if cond c then Just (c, cs) else Nothing
many :: Parser a -> Parser [a]
many p = Parser $ \s ->
case parse p s of
Nothing -> Just ([], s)
Just (c, cs) -> let Just (cc, cs') = parse (many p) cs
in Just (c:cc, cs')
string :: String -> Parser String
string str = Parser $ \s -> if isPrefixOf str s
then Just (str, drop (length str) s)
else Nothing
instance Functor Parser where
fmap f (Parser g) = Parser $ \s ->
case g s of
Nothing -> Nothing
Just (r, remain) -> Just (f r, remain)
instance Applicative Parser where
pure a = Parser $ \s -> Just (a, s)
-- (<*>) :: f (a -> b) -> f a -> f b
(Parser f) <*> (Parser g) = Parser $ \s ->
case f s of
Nothing -> Nothing
Just (ab, remain) -> case g remain of
Nothing -> Nothing
Just (r, remain1) -> Just (ab r, remain1)
instance Semigroup a => Semigroup (Parser a) where
(Parser p1) <> (Parser p2) = Parser $ \s ->
case p1 s of
Nothing -> Nothing
Just (r1, s1) -> case p2 s1 of
Nothing -> Nothing
Just (r2, s2) -> Just (r1 <> r2, s2)
instance (Monoid a, Semigroup (Parser a))=> Monoid (Parser a) where
mempty = Parser $ \s -> Just (mempty, s)
mappend = (<>)
a = satisfy isAlpha
b = many (satisfy isDigit)
λ> parse a "k345"
Just ('k',"345")
λ> parse b "12345 abc"
Just ("12345"," abc")
λ> parse (a *> b) "k1234 7"
Just ("1234"," 7")
λ> parse (string "k" <> b) "k1234 7"
Just ("k1234"," 7")
所以也许您应该找一些教程并尝试熟悉 Functor
、Applicative
和 Monad
。你看,你可以为你的 Parser
类型实现一个 Monoid
的实例,然后你可以使用 (<>)
将你的解析结果组合在一起。