Suppose I'm expecting input of this form:
A foo
B bar
C baz
and I'd like to read it into a record like { a: string; b: string; c: string }.
The best functional way I can think of doing this is like this:
let rec fold rec = try let key, val = read_pair () in match key with | "A" -> fold { rec with a = val } | "B" -> fold { rec with b = val } | "C" -> fold { rec with c = val } with End_of_input -> rec in fold empty_record
This is ok, but the "empty_record" bit is a hack; I want it to be an error for any of A, B, or C to not be present, and here they just keep the fields' default values (whatever was in empty_record).
One solution it to change the record into using option types ({ a: string option; etc. }) but like I said, it's an error any of the fields to be left undefined and the rest of the code (which consumes the record) shouldn't need to deconstruct the options into their values.
What's a good way to do this? I'm tempted to just use mutable fields on the record, but that's also hacky.