Usa lentes para actualizar registros anidados (específico de los lenguajes con datos inmutables).
Actualizar los campos de registros anidados e inmutables es bastante molesto. El código para estos casos es tan engorroso como profunda es la estructura. Si tienes, por ejemplo, un Person que contiene un Address, el cual tiene una Street, que a su vez tiene un Number, actualizar el Number requiere crear una Street nueva con el nuevo Number, luego un Address nuevo con la nueva Street y, por último, un Person nuevo con el nuevo Address. ¿Ya te has liado?
Una solución a este problema es usar lentes.
Implementa varias funciones de acceso a registros usando lentes. La suite de tests también te permite prescindir por completo de las lentes, para que puedas experimentar con distintos enfoques.
Las lentes no se usan mucho en Roc porque la sintaxis de actualización de registros cubre muy bien la mayoría de los casos de uso. Por ejemplo, fíjate en este registro anidado:
bob = { hair: { color: Brown, length: Long }, mouth: Smiling, height: 6.0 }
Ahora vamos a cortarle el pelo a Bob:
new_bob = { ..bob, hair: { ..bob.hair, length: Short } }
¡No hacen falta lentes! Dicho esto, aunque las lentes son poco frecuentes en Roc, son habituales en otros lenguajes como Haskell y Scala, así que puede que sientas curiosidad por saber cómo se podrían implementar en Roc. También es una buena forma de practicar algunas funcionalidades avanzadas de Roc, como los tipos parametrizados y los registros que contienen funciones. De hecho, esta es una forma de representar una lente en Roc:
Lens(whole, part) := {
get : whole -> part,
set : whole, part -> whole,
}
Este es un tipo parametrizado: whole y part podrían ser de cualquier tipo. Normalmente, whole es un registro, mientras que part puede ser cualquier tipo de campo. El campo get contiene una función que devuelve un valor part concreto del whole dado, mientras que el campo set contiene una función que devuelve una copia del whole dado, pero con un valor part concreto sustituido por el part dado.
Por ejemplo, esta es una lente para obtener o establecer el pelo de una persona:
hair_lens = {
get: |person| person.hair,
set: |person, hair| { ..person, hair },
}
Podemos usar esta lente para centrarnos en el pelo de Bob, así:
bob_hair = bob |> hair_lens.get
Y podemos cambiarle el pelo así:
new_hair = { ..bob.hair, length: Short }
new_bob = bob |> (hair_lens.set)(new_hair)
Nota: los paréntesis que rodean hair_lens.set son obligatorios: sin ellos, Roc buscaría una función llamada set en el tipo de hair_lens.
Las lentes resultan especialmente útiles cuando empiezas a componerlas, ya que te permiten obtener y establecer partes anidadas a gran profundidad. Esto se puede conseguir implementando una función como esta:
compose : Lens(outer, inner), Lens(inner, part) -> Lens(outer, part)
Una vez implementada esta función, puedes usarla para crear una lente de longitud del pelo como esta:
length_lens = {
get: |hair| hair.length,
set: |hair, length| { ..hair, length },
}
hair_length_lens = compose(hair_lens, length_lens)
Ahora puedes darle a Bob otro corte de pelo:
set_hair_length = hair_length_lens.set
new_bob = bob |> set_hair_length(Short)
También puede que quieras implementar una función que te permita aplicar cualquier transformación a una parte anidada:
over : Lens(whole, part), whole, (part -> part) -> whole
Una vez implementada, puedes usar over así:
cut_hair = |current_length| match current_length {
Long => Short
Short => Bald
Bald => Bald
}
new_bob = hair_length_lens |> over(bob, cut_hair)
En este ejercicio, los tests comprobarán que tu código es capaz de modificar diversas partes anidadas del siguiente registro anidado:
test_person : Person
test_person = {
name: { forenames: "Jane Joanna", surname: "Doe" },
birth: {
born_at: { street: "Longway", house_number: 1024, place: "Springfield", country: "United States" },
born_on: { year: 1984, month: 4, day: 12 },
},
address: { street: "Shortlane", house_number: 2, place: "Fallmeadow", country: "Canada" },
}
Te recomendamos que primero pases los tests usando la sintaxis de actualización de registros de Roc y que después pruebes a usar lentes.
Regístrate en Exercism para aprender y dominar Roc con 125 ejercicios y mentoría humana real, todo gratis.