I want to parse a string in a recursive data structure using F #. In this question, I will give a simplified example that will shorten the core of what I want to do.
I want to parse a string of nested square brackets in a record type:
type Bracket = | Bracket of Bracket option
So:
- "[]" β
Bracket None - "[[]]" β
Bracket ( Some ( Bracket None) ) - "[[[]]]" β
Bracket ( Some ( Bracket ( Some ( Bracket None) ) ) )
I would like to do this using parser combinators in the FParsec library. Here is what I still have:
let tryP parser = parser |>> Some <|> preturn None /// Parses up to nesting level of 3 let parseBrakets : Parser<_> = let mostInnerLevelBracket = pchar '[' .>> pchar ']' |>> fun _ -> Bracket None let secondLevelBracket = pchar '[' >>. tryP mostInnerLevelBracket .>> pchar ']' |>> Bracket let firstLevelBracket = pchar '[' >>. tryP secondLevelBracket .>> pchar ']' |>> Bracket firstLevelBracket
I even have Expecto tests:
open Expecto [<Tests>] let parserTests = [ "[]", Bracket None "[[]]", Bracket (Some (Bracket None)) "[[[]]]", Bracket ( Some (Bracket (Some (Bracket None)))) ] |> List.map(fun (str, expected) -> str |> sprintf "Trying to parse %s" |> testCase <| fun _ -> match run parseBrakets str with | Success (x, _,_) -> Expect.equal x expected "These should have been equal" | Failure (m, _,_) -> failwithf "Expected a match: %s" m ) |> testList "Bracket tests" let tests = [ parserTests ] |> testList "Tests" runTests defaultConfig tests
The problem, of course, is how to handle an arbitrary level of nesting - the above code only works for three levels. The code I would like to write:
let rec pNestedBracket = pchar '[' >>. tryP pNestedBracket .>> pchar ']' |>> Bracket
But F # does not allow this.
I completely bark the wrong tree, how can I solve this (I understand that there are simpler ways to solve this particular problem)?
source share