Сначала немного предыстории. В настоящее время я изучаю кое-что о комбинаторах монадического синтаксического анализатора. Пока я пытался перенести функцию 'chainl1' из этой статьи ( с. 16-17), я пришел к такому решению:
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)))