4

このパーサータイプがあるとしましょう:

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

そして、このアトミック パーサー ユニット:

satisfy :: ( Char -> Bool ) -> Parser Char
satisfy g = Parser $ \stream -> case stream of
    (x:xs) | g x -> Just ( x, xs )
    otherwise    -> Nothing

パーサーは、次の 3 つのインターフェイスを実装します。

instance Functor Parser where
    fmap g ( Parser p ) = Parser $ \xs0 -> p xs0 >>= \(x,xs) -> return ( g x, xs )


instance Applicative Parser where
    pure a                      = Parser $ \xs0 -> Just ( a, xs0 )
    (Parser p1) <*> (Parser p2) = Parser $ \xs0 -> do
        (x1, xs1) <- p1 xs0
        (x2, xs2) <- p2 xs1
        return ( x1 x2, xs2 )

instance Alternative Parser where
    empty                        = Parser $ const Nothing
    (Parser p1) <|> (Parser p2)  = Parser $ \ss -> let ss1 = p1 ss in case ss1 of
        Nothing  -> p2 ss
        _        -> ss1

私が理解しているように、より高いレベルの抽象化にポップアップしsatisfy、アプリケーション インターフェイスを使用して連鎖することにより、より複雑なパーサーを構築できるようになりました。例:

-- | A parser that parses the first two chars in the stream if they are upper case
uParser = satisfy isUpper
parser1 = ( (:) <$> uParser ) <*> ( (\x -> [x]) <$> uParser )
runParser parser1 "HEllo" = Just ("HE","llo")
runParser parser1 "Hello" = Nothing

これはすばらしいことですが、小文字に遭遇するまでパーサーがストリーム内のすべての大文字を解析するように計算を構築したい場合はどうすればよいでしょうか? 使用事例:

runParser idealParser "hello"             = Nothing
runParser idealParser "HEllo"             = Just ("HE","llo")
runParser idealParser "HELLOIAMnotincaps" = Just ("HELLOIAM", "notincaps")

この決定されない長さの概念をどのように表現すればよいでしょうか?

4

1 に答える 1

7

インスタンスがあるのでAlternative、単純に を使用Control.Applicative.someして 1 つ以上のオカレンスのリストを一致させることができます。

> runParser (some uParser) "hello"
Nothing
> runParser (some uParser) "HEllo"
Just ("HE","llo")
> runParser (some uParser) "HELLOIAMnotincaps"
Just ("HELLOIAM","notincaps")

手動で実装するには、相互に再帰的な 2 つのパーサーを使用できます。

zeroOrMore = oneOrMore <|> pure []
oneOrMore  = (:) <$> uParser <*> zeroOrMore
于 2013-04-15T01:29:30.697 に答える