静态地"扩展"记录数据类型而没有间接麻烦

Pti*_*val 14 ocaml records functional-programming nested sml

我目前正在处理一个三级流程,我需要一些信息才能访问和更新.信息也是三级的,这样一个级别的过程可能需要在其级别和更高级别访问/更新信息.

type info_0 = { ... fields ... }
type info_1 = { ... fields ... }
type info_2 = { ... fields ... }
Run Code Online (Sandbox Code Playgroud)

fun0会用a做一些东西info_0,然后将它传递给fun1a info_1,然后返回结果info_0并继续,fun1用另一个调用另一个info_1.同样的情况发生在较低级别.


我目前的代表有

type info_0 = { ... fields ... }
type info_1 = { i0: info_0; ... fields ... }
type info_2 = { i1: info_1; ... fields ... }
Run Code Online (Sandbox Code Playgroud)

fun2,更新info_0变得非常混乱:

let fun2 (i2: info_2): info_2 =
  {
    i2 with
      i1 = {
        i2.i1 with
          i0 = update_field0 i2.i1.i0
      }
  }
Run Code Online (Sandbox Code Playgroud)

更简单的是:

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)
Run Code Online (Sandbox Code Playgroud)

最后的解决方案看起来不错吗?

是否有更好的解决方案来解决这类问题?(例如,我可以编写一个可以处理更新a的函数,field0无论它是否处理a info_0,info_1或者info_2)

OCaml模块会有帮助吗?(我可以包括一个Sig0内部Sig1......)

pad*_*pad 10

您需要的是更新嵌套的不可变数据结构的惯用方法.我不知道OCaml中的任何相关工作,但 Scala/Haskell中有一些技术可用,包括Zippers,Tree rewritingFunctional镜头:

更新嵌套结构的更清洁方法

是否有用于更新嵌套数据结构的Haskell习惯用法?

对于OCaml的后代F#,功能镜头提供了一个很好的解决方案.因此,镜片是这里最相关的方法.您可以从这个线程中获得使用它的想法:

更新嵌套的不可变数据结构

因为F#记录语法几乎与OCaml的语法相同.

编辑:

作为@Thomas在他的评论中提到的,在OCaml中可使用的镜头的完整实现在这里.特别是,gapiLens.mli符合我们的利益.

  • 如果你想要镜头,你可以找到一个非常完整的实现[这里](https://github.com/astrada/gapi-ocaml) (4认同)

Jef*_*eld 5

您似乎希望能够将更复杂的值视为更简单的值.这(或多或少)是OO模型的本质.我经常试图避免使用OCaml的OO子集,除非我真的需要它,但它似乎确实满足了你的需求.你会有一个对应的基类info_0.该类info_1将是它的子类info_0,并且info_2将是它的子类info_1.无论如何,这是值得思考的.