1

data CI = CI Int Int给定一个表示复数的数据类型,我想为 CI 构建一个解析器,它可以转换"a"CI a 0和。例如,我想要一个返回值的函数(理想情况下,类似的东西也可以)。我还想让 CI 成为."(a,b)"CI a bparseCIrunParser parseCI "(1,2)"[(CI 1 2, "")]read

我想使用下面代码中的函数和定义来做到这一点(基本上,没有任何先进的东西,比如 Parsec),但我不知道从哪里开始。一些让我走上正轨的起始代码和/或提示会很有帮助。我不是在寻找完整的答案,因为我想自己弄清楚。

module Parser where
import Control.Applicative
import Control.Monad

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

satisfy :: (Char -> Bool) -> Parser Char
satisfy f = Parser $ \s -> case s of
    [] -> []
    a:as -> [(a,as) | f a]

char :: Char -> Parser Char
char = satisfy . (==)

string :: String -> Parser String
string str = Parser $ \s -> [(t,u) | let (t,u) = splitAt (length str) s, str == t]

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

instance Applicative Parser where
    pure a = Parser $ \s -> [(a,s)]
    af <*> aa = Parser $ \s ->
        [ (f a,u) 
        | (f,t) <- runParser af s
        , (a,u) <- runParser aa t
        ]

instance Alternative Parser where
    empty = Parser $ \s -> []
    p1 <|> p2 = Parser $ (++) <$> runParser p1 <*> runParser p2`

instance Monad Parser where
    return = pure
    ma >>= f = Parser $ \s ->
       [ (b,u) 
       | (a,t) <- runParser ma s
       , (b,u) <- runParser (f a) t
       ]

instance MonadPlus Parser where
    mzero = empty
    mplus = (<|>)
4

1 回答 1

2

您可能已经看过它,但如果您还没有看过:Haskell 中的 Monadic Parsing 会像这样设置解析。

由于您有两种不同的解析方式CI,因此您可能希望将其视为两个问题:制作一个parseCI1解析"a"为的解析器CI a 0和制作另一个parseCI2解析"(a,b)"为的解析器CI a b。然后,您可以将它们与

parseCI = parseCI1 <|> parseCI2

对于这两个子解析器,您将需要某种解析整数的方法:parseInt :: Parser Int. 在制作 时parseInt,您可能希望使用 、 、 和可能的某种组合satisfyisDigit取决于readsome如何解决这个问题)。


完成后,创建一个readCI实例会更简单一些parseCI

instance Read CI where
  readsPrec _ = runParser parseCI
于 2016-11-14T04:15:18.380 回答