在Haskell,我可以写:
token: Parser a -> Parser a
token p = do space
v <- p
space
return v
在F#中,我走到了这一步:
let token = compose {
let! _ = space
let! v = parser
let! _ = space
return v
}
换句话说,我必须引入这个未使用的let! _ =
绑定来丢弃“space”解析器(monad)的解析值,这是我不需要的。
如何在F#中避免这些无用的绑定?我尝试过使用do!,但是我收到错误(因为我的>>=
函数不接受类型单位而是'a):
let (>>=) (p: Parser<'a>) (f: 'a -> Parser<'b>) : Parser<'b>
这是我的构建器定义:
type ParserComposer() =
member x.Bind(p, f) = p >>= f
member x.Return(y) = ret y
member x.Zero() = failure
我是否需要定义>>
功能?将Combine()添加到构建器?任何想法如何做到这一点?代码示例?
答案 0 :(得分:5)
假设space
的返回类型是Parser<unit>
(如果它不代表返回某些结果的解析器,那么它是有意义的)你可以写:
let token = compose {
do! space
let! v = parser
do! space
return v
}
这只是你所写内容的语法糖 - 所以do! e
被翻译为let! _ = e
,而parser.Bind(e, fun _ -> ...)
又翻译为Combine
。我有Additive parsers on Try Joinads的示例,其中还定义了do!
以及一些(可能)有用的内容,但Bind
关键字只需要{{1}}。