Pierwsze tło. Obecnie uczę się kilku rzeczy o kombinatorach parserów monadycznych. Chociaż starałem się przekazać funkcję „chainl1” z this paper (str. 16-17), wpadłem na to rozwiązanie:Funkcje rekursywne w wyrażeniach obliczeniowych
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
}
testowałem funkcji z jakiegoś dużego wejście i dostał StackOverflowException. Teraz zastanawiam się, czy jest możliwe przepisanie funkcji rekursywnej, która używa pewnej ekspresji obliczeniowej, w taki sposób, że używa rekursji ogonowej?
Kiedy rozszerzam wyrażenie obliczeniowe, nie widzę, jak byłoby to ogólnie możliwe.
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)))
To pozbywa się rekursji za pomocą kodu użytkownika, ale w mojej implementacji tutaj http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!1772. Wciąż to StackOverflows poprzez samą implementację parsera. Teraz będę zmotywowany do zbadania "parserów z kontynuacjami" ... – Brian
Czy FParsec http://www.quanttec.com/fparsec/ sobie z tym poradzi? – Brian
Brian, użyłem również twojej serii blogów jako źródła do nauki. To pomogło dużo. Tymczasem porównałem odpowiedź Mau'a ("seq") z moim parserem. I myślę, że metoda opóźnienia w monadzie jest importowana. Ale naprawdę nie wiem. FParsec używa "while" ... ale chcę użyć rozwiązania funkcjonalnego: D – PetPaulsen