具有两个参数的构造函数的应用样式解析器

kru*_*pen 2 haskell parsec applicative

我想在尖括号中为逗号分隔的值对编写解析器.我用它采用以下方法:

pair p1 p2 = do
    x1 <- p1
    comma
    x2 <- p2
    return (x1, x2)

data Foo = Foo (Bar, Bar)

foo :: Parser Foo
foo = Foo <$> (angles $ pair bar bar)
Run Code Online (Sandbox Code Playgroud)

但是我更喜欢Foo构造函数采用两个参数而不是元组:

data Foo = Foo Bar Bar
Run Code Online (Sandbox Code Playgroud)

编写这样一个解析器的最佳方法是什么?理想情况下,我想重用标准的Parsec解析器,angles并尽可能使用applicative.

Dan*_*her 8

编写这样一个解析器的最佳方法是什么?理想情况下,我想重用标准Parsec解析器这样的角度,并尽可能使用applicative.

在应用程序风格中,您的解析器将是

foo = angles $ Foo <$> bar <* comma <*> bar
Run Code Online (Sandbox Code Playgroud)

从里到外,a bar被解析,然后是a comma,被丢弃,而另一个bar,然后构造函数Foo被应用于两个被解析的bars.最后,所有都被包裹在angles组合器中,以便形成一个字符串

< bar , bar >
Run Code Online (Sandbox Code Playgroud)

被解析(bar应该使用尾随空格).

将解析器的结果*><*应用组合器相结合的解析器消除了对组合器的需要,pair并且很容易推广给构造函数采用任意数量的参数.

正如CA McCann在评论中提到的那样,(<$)组合器(它是GHC的Functor类实现的一部分,具有默认实现(<$) = fmap . const;但它不是语言标准的一部分)也是有用的,如果你想忽略一个前导令牌.使用它,你可以写

Foo <$ ignoreMe <*> bar <* comma <*> baz
Run Code Online (Sandbox Code Playgroud)

这比使用括号更好

Foo <$> (ignoreMe *> bar) <* comma <*> baz
Run Code Online (Sandbox Code Playgroud)

或者pure,

pure Foo <* ignoreMe <*> bar <* comma <*> baz
Run Code Online (Sandbox Code Playgroud)

如果没有它,将以某种形式要求.

  • 此外,对于要忽略的前导令牌,可以使用类似`Foo <$ keywordFoo <*> bar <*逗号<*> baz`的内容.我忘记了`(<$)`的定义以及导出它的地方. (2认同)