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
…