静态地“扩展”没有间接麻烦的记录型数据类型
我目前正在处理一个三级流程,我需要一些信息来进行访问和更新。该信息也是三级的,这样一来,一个级别的进程可能需要访问/更新其级别和更高级别的信息。
type info_0 = { ... fields ... }
type info_1 = { ... fields ... }
type info_2 = { ... fields ... }
fun0
将使用 info_0
执行一些操作,然后将其与 info_1
一起传递给 fun1
,然后返回生成的 info_0
并继续,用另一个 info_1
调用另一个 fun1
。 同样的情况也发生在较低级别。
我当前的表示
type info_0 = { ... fields ... }
type info_1 = { i0: info_0; ... fields ... }
type info_2 = { i1: info_1; ... fields ... }
在 fun2
中,更新 info_0
变得非常混乱:
let fun2 (i2: info_2): info_2 =
{
i2 with
i1 = {
i2.i1 with
i0 = update_field0 i2.i1.i0
}
}
更简单的事情是:
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)
最后一个解决方案看起来不错吗?
对于此类问题还有更好的解决方案吗? (例如,我可以编写一个可以处理更新 field0
的函数,无论它是处理 info_0
、info_1
还是info_2
)
OCaml 模块有帮助吗? (例如,我可以在 Sig1
内包含一个 Sig0
...)
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...)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您需要的是一种更新嵌套不可变数据结构的惯用方法。
我不知道 OCaml 中的任何相关工作,但是Scala/Haskell 中有一些可用的技术,包括 Zippers、树重写 和功能镜头:更新嵌套的更简洁的方法结构
是否有 Haskell 习惯用法用于更新嵌套数据结构?
对于 F#(OCaml 的后代),功能性镜头提供了一个很好的解决方案。因此,镜头是这里最相关的方法。 线程中了解使用它的想法:
更新嵌套不可变数据结构
您可以从此 F# 记录语法与 OCaml 几乎相同。
编辑:
正如@Thomas在评论中提到的,OCaml中有一个完整的镜头实现这里。特别是, gapiLens.mli 是我们的兴趣。
What you need is an idiomatic way of updating nested immutable data structures.
I don't know any relevant work in OCaml, butthere 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.
您似乎希望能够将更复杂的值视为更简单的值。这(或多或少)是面向对象模型的本质。我通常会尝试避免 OCaml 的 OO 子集,除非我真的需要它,但它似乎确实满足了您的需求。您将有一个与
info_0
对应的基类。类info_1
将是info_0
的子类,而info_2
将是info_1
的子类。无论如何,这都值得思考。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 classinfo_1
would be a subclass ofinfo_0
, andinfo_2
would be a subclass ofinfo_1
. It's worth thinking about, anyway.正如 Jeffrey Scofield 建议的 ,您可以通过使用类来省去使用和更新时的麻烦:使
info_1
成为 的派生类和子类型info_0
,等等。这种直接对象方法的缺点是,如果更新任何字段,则对象中的所有数据都会被复制;您无法在
x
和y
之间共享info_0
片段。您可以使用对象并保留设计中记录的共享行为,但定义时的样板和恒定的运行时开销会变得更大。
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, ofinfo_0
, and so on.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 betweenx
andy
.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.