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")

所以也许您应该找一些教程并尝试熟悉 FunctorApplicativeMonad。你看,你可以为你的 Parser 类型实现一个 Monoid 的实例,然后你可以使用 (<>) 将你的解析结果组合在一起。