functional-programming nested ocaml sml records

functional programming - Estáticamente "extienda" un tipo de datos sin errores indirectos



functional-programming nested (3)

Parece que quieres la capacidad de tratar un valor más complejo como si fuera más simple. Esta es (más o menos) la esencia del modelo OO. Normalmente trato de evitar el subconjunto OO de OCaml a menos que realmente lo necesite, pero parece que satisface sus necesidades aquí. Tendría una clase base correspondiente a info_0 . La clase info_1 sería una subclase de info_0 , e info_2 sería una subclase de info_1 . Vale la pena pensar, de todos modos.

Actualmente estoy trabajando con un proceso de tres niveles para el cual necesito que se acceda y actualice cierta información. La información también tiene tres niveles, de tal manera que un proceso en un nivel puede necesitar acceder / actualizar información en su nivel y en niveles más altos.

type info_0 = { ... fields ... } type info_1 = { ... fields ... } type info_2 = { ... fields ... }

fun0 hará algunas cosas con un info_0 , luego lo pasará a fun1 junto con un info_1 , luego obtendrá la información resultante_0 y procederá, llamando a otro fun1 con otra info_1 . Lo mismo ocurre en el nivel inferior.

Mi representación actual tiene

type info_0 = { ... fields ... } type info_1 = { i0: info_0; ... fields ... } type info_2 = { i1: info_1; ... fields ... }

En fun2 , actualizar info_0 es bastante complicado:

let fun2 (i2: info_2): info_2 = { i2 with i1 = { i2.i1 with i0 = update_field0 i2.i1.i0 } }

Algo más simple sería:

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)

¿La última solución se ve bien?

¿Hay una solución aún mejor para este tipo de problema? (por ejemplo, uno donde podría escribir una función que puede manejar la actualización de un field0 , sin importar si se trata de un info_0 , info_1 o info_2 )

¿Ayudarían los módulos OCaml? (Podría incluir un Sig0 dentro de Sig1 por ejemplo ...)


Lo que necesita es una forma idiomática de actualizar las estructuras de datos inmutables anidadas . No conozco ningún trabajo relevante en OCaml, pero hay algunas técnicas disponibles en Scala / Haskell que incluyen cremalleras , reescritura de árbol y lentes funcionales :

Manera más limpia de actualizar estructuras anidadas

¿Hay un modismo de Haskell para actualizar una estructura de datos anidada?

Para F #, un descendiente de OCaml, las lentes funcionales ofrecen una buena solución. Por lo tanto, lentes es el enfoque más relevante aquí. Puedes tener la idea de usarlo desde este hilo:

Actualización de estructuras de datos inmutables anidadas

ya que la sintaxis del registro F # es casi la misma que la de OCaml.

EDITAR:

Como @Thomas mencionó en su comentario, hay una implementación completa de lentes en OCaml disponible aquí . Y particularmente, gapiLens.mli es de nuestro interés.


Como sugirió Jeffrey Scofield , puede guardar la molestia al momento de usar y actualizar mediante el uso de clases: make info_1 una clase derivada y un subtipo de info_0 , y así sucesivamente.

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 …

La desventaja de este enfoque de objeto directo es que todos los datos de un objeto se copian si actualiza alguno de los campos; no puedes compartir las piezas de info_0 entre info_0 y .

Puede usar objetos y conservar el comportamiento de uso compartido de su diseño con registros, pero la repetición en tiempo de definición y la sobrecarga de tiempo de ejecución constante se vuelven más grandes.

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 …