Parsers can be a great tool for collecting metadata about a project or automating some of the processes in your workflow. Regardless of whether the parser is a script for gathering a subset of data or a full blown transpiler, relying on regular expressions, string methods, and indices to parse the information you need can get complicated.
FParsec is a parser combinator library written in F# and is an alternative means for parsing text into consumable data structures. Using functional programming techniques like function composition and pattern matching, FParsec provides a way for you to write parsers quickly, easily, and with a syntax that clearly communicates your intent.
This session offers an introduction to the FParsec library as well as the functional programming concepts needed to start using parser combinators. By working through an example parser from first principles towards a more complex use case, you will learn the tools and techniques provided by F# and FParsec for writing accurate and maintainable parsing applications.
2. A parser is an application or script
that takes in data, usually in the
form of text or a stream, and
produces a data structure to
represent syntactical relationship.
29. type Parser<’TResult, ‘TUserState> =
CharStream<‘TUserState> -> Reply<’TResult>
val run:
Parser<’a, unit> -> string -> ParserResult<’a,
unit>
30. type Parser<’TResult, ‘TUserState> =
CharStream<‘TUserState> -> Reply<’TResult>
val run:
Parser<’a, unit> -> string -> ParserResult<’a,
unit>
type ParserResult<’Result, ‘UserState> =
| Success of ’Result * ‘UserState * Position
| Failure of string * ParserError * ‘UserState
31. let test p str =
match run p str with
| Success(result, state, pos) -> ...
| Failure(errMsg, error, state) -> ...
32. let test p str =
match run p str with
| Success(result, _, _) ->
printfn “Success: %A” result
| Failure(errMsg, _, _) ->
printfn “Failure: %s” errMsg
48. type UserState =
{ PhoneCount: int
AddressCount: int }
with
static member Default =
{ PhoneCount = 0
AddressCount = 0 }
49. let incrementPhoneNumber =
let incrementPhone us =
{ us with PhoneCount = us.PhoneCount + 1 }
updateUserState incrementPhone
50. let incrementPhoneNumber =
let incrementPhone us =
{ us with PhoneCount = us.PhoneCount + 1 }
updateUserState incrementPhone
let incrementStreetAddress =
let incrementAddress us =
{ us with AddressCount = us.AddressCount + 1 }
updateUserState incrementPhone
51. let pcontactinfo =
[ paddress .>> incrementStreetAddress .>> spaces
phonenumber .>> incrementPhoneNumber .>> spaces ]
|> choice
|> many
53. ● Download the .NetCore SDK
● Create a directory for your parser scripts
● While in the directory, download Paket *
*(Paket is an alternative solution to package management in dotnet)
54. ● Run the dotnet paket init command
● Add nuget FParsec to the paket.dependencies
file created by paket
● Run dotnet paket install
● Run dotnet paket generate-load-scripts
55. Alternatively, you can add generate_load_scripts: true
at the top of your paket.dependencies file before
running dotnet paket install which will automatically
generate the load scripts.
56. ● Create an F# script file in the parent directory of
your project (ex. parsers.fsx)
● At the top of the file add the following code to
load the dll references for FParsec and open the
FParsec namespace
#load @”.paketloadnetcoreapp3.0main.group.fsx”
open FParsec