先来点背景。我目前正在学习一些关于单子解析器组合器的东西。当我尝试从本文(第 16-17 页)转移“chainl1”函数时,我想出了这个解决方案:
let chainl1 p op = parser {
let! x = p
let rec chainl1' (acc : 'a) : Parser<'a> =
let p' = parser {
let! f = op
let! y = p
return! chainl1' (f acc y)
}
p' <|> succeed acc
return! chainl1' x
}
我用一些大的输入测试了这个函数,得到了一个 StackOverflowException。现在我想知道,是否可以重写一个递归函数,它使用一些计算表达式,以某种方式使用尾递归?
当我扩展计算表达式时,我看不出它通常是如何实现的。
let chainl1 p op =
let b = parser
b.Bind(p, (fun x ->
let rec chainl1' (acc : 'a) : Parser<'a> =
let p' =
let b = parser
b.Bind(op, (fun f ->
b.Bind(p, (fun y ->
b.ReturnFrom(chainl1' (f acc y))))))
p' <|> succeed acc
b.ReturnFrom(chainl1' x)))