Haskell - Parsec :: 解析空格直到字符串文字

3
我目前正在尝试使用Parsec在Haskell中设计一个解析器。 声明类型的语法应该类似于这样:
Fruit is a Apple

类型也应该能够拥有参数:

Fruit a b is a Apple

在这里:

  • Fruit 的类型为 Name
  • a b 的类型为 [Parameter]
  • Apple 的类型为 Value

问题在于,我的解析器目前不知道何时停止解析 parameters 并开始解析 value

以下是代码:

newtype Name = Name String deriving (Show)
newtype Parameter = Parameter String deriving (Show)
newtype Value = Value String deriving (Show)

data TypeAssignment = TypeAssignment Name [Parameter] Value deriving (Show)

-- first variant using `sepBy`
typeAssigment :: Parser TypeAssignment
typeAssigment =
    TypeAssignment
    <$> name
    <*> (space *> parameter `sepBy` space)
    <*> (string "is a" *> value)

-- second variant using manyTill
typeAssigment2 :: Parser TypeAssignment
typeAssigment2 =
    TypeAssignment 
    <$> name
    <*> (space *> manyTill parameter (string "is a"))
    <*> value

name :: Parser Name
name = Name <$> word

parameter :: Parser Parameter
parameter = Parameter <$> word

value :: Parser Value
value = Value <$> word

word :: Parser String
word = (:) <$> letter <*> many (letter <|> digit)

我已经尝试以我知道的两种方式(一次使用sepBy和一次使用manyTill)解析参数/值,但都失败了,几乎出现了parse-error:

*EParser> parseTest typeAssigment "Fruit a b is a Apple"
parse error at (line 1, column 21):
unexpected end of input
expecting space or "is a"

*EParser> parseTest typeAssigment2 "Fruit a b is a Apple"
parse error at (line 1, column 8):
unexpected " "
expecting letter, digit or "is a"
1个回答

2
typeAssignment1存在的问题是"is""a"都是合法的parameter解析。因此,参数解析器会一直解析输入,直到没有任何内容可解析,然后出现错误。实际上,如果你仔细查看该错误,你会发现这是真的:解析器期望的是空格(用于更多参数)或“is a”(整个解析器的终端)。

另一方面,typeAssignment2非常接近,但似乎没有正确处理空格。为了解析多个parameter,需要解析这些参数之间的所有space,而不仅仅是第一个。

我认为以下替代方案可以解决问题:

typeAssigment3 :: Parser TypeAssignment
typeAssigment3 =
    TypeAssignment 
    <$> name
    <*> manyTill (space *> parameter) (try $ string "is a")
    <*> (space *> value)

1
谢谢,这对我很有帮助!需要进行轻微修改,然后它就完美地适用于我了:typeAssigment3 :: Parser TypeAssignment typeAssigment3 = TypeAssignment <$> name <*> (space *> manyTill (parameter <* space) (P.try $ string "is a")) <*> (space *> value) - Giftzwerg02
哦,是的,谢谢你指出来(这就是我没有亲自测试代码的后果)。我更新了答案,包括 try - DDub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接