I am currently working with a three-level process for which I need some information to flow being accessed and updated. The information is also three-leveled, in such a way that a process at one level may need to access/update information at its level and at higher levels.
type info_0 = { ... fields ... }
type info_1 = { ... fields ... }
type info_2 = { ... fields ... }
fun0
will do some stuff with an info_0
, then pass it to fun1
along with an info_1
, then get back the resulting info_0
and proceed, calling another fun1
with another info_1
.
The same happens at the lower level.
My current representation has
type info_0 = { ... fields ... }
type info_1 = { i0: info_0; ... fields ... }
type info_2 = { i1: info_1; ... fields ... }
In fun2
, updating info_0
get pretty messy:
let fun2 (i2: info_2): info_2 =
{
i2 with
i1 = {
i2.i1 with
i0 = update_field0 i2.i1.i0
}
}
Something simpler would be:
type info_0 = { ... fields ... }
type info_1 = { ... fields ... }
type info_2 = { ... fields ... }
type info_01 = info_0 * info_1
type info_012 = info_0 * info_1 * info_2
let fun2 (i0, i1, i2): info_012 =
(update_field0 i0, i1, i2)
Does the last solution look good?
Is there an even better solution to this kind of problem? (for instance, one where I could write a function that can handle updating a field0
, no matter whether it's dealing with a info_0
, info_1
or info_2
)
Would OCaml modules help? (I could include a Sig0
inside Sig1
for instance...)
What you need is an idiomatic way of updating nested immutable data structures. I don't know any relevant work in OCaml, but there are a few techniques available in Scala/Haskell including Zippers, Tree rewriting, and Functional lenses:
Cleaner way to update nested structures
Is there a Haskell idiom for updating a nested data structure?
For F#, a descendant of OCaml, functional lenses gives a nice solution. Therefore, lenses is the most relevant approach here. You can get the idea of using it from this thread:
Updating nested immutable data structures
since F# record syntax is almost the same as that of OCaml.
EDIT:
As @Thomas mentioned in his comment, there is a complete implementation of lenses in OCaml available here. And particularly, gapiLens.mli is of our interest.
You seem to want the ability to treat a more complex value as though it was a simpler one. This is (more or less) the essence of the OO model. I usually try to avoid the OO subset of OCaml unless I really need it, but it does seem to meet your needs here. You would have a base class corresponding to info_0
. The class info_1
would be a subclass of info_0
, and info_2
would be a subclass of info_1
. It's worth thinking about, anyway.
As Jeffrey Scofield suggested, You can save the hassle at use and update time by using classes: make info_1
a derived class, and a subtype, of info_0
, and so on.
class info_1 = object
inherit info_0
val a_1_1 : int
…
method update_a_1_1 v = {<a_1_1 = v>}
end
…
let x : info_1 = new info_1 … in
let y = x#update_a_1_1 42 in
…
The downside of this direct object approach is that all the data in an object is copied if you update any of the fields; you can't share the info_0
pieces between x
and y
.
You can use objects and retain the sharing behavior from your design with records, but the boilerplate at definition time and the constant run-time overhead become larger.
class info_1 = object
val zero : info_0
method get_a_0_1 = zero#get_a_0_1
method update_a_0_1 = {<zero = zero#update_a_0_1>}
val a_1_1 : int
method get_a_1_1 = a_1_1
method update_a_1_1 v = {<a_1_1 = v>}
end
let x : info_1 = new info_1 … in
let y = x#update_a_1_1 42 in
…
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With