Tracks
/
Roc
Roc
/
Ejercicios
/
Persona lente
Persona lente

Persona lente

Intermedia

Instrucciones

Usa lentes para actualizar registros anidados (algo específico de los lenguajes con datos inmutables).

Actualizar los campos de registros anidados e inmutables es bastante molesto. El código para esos casos es tan engorroso como profunda es la estructura. Si tienes, digamos, un Person, que contiene un Address, que tiene un Street, que tiene un Number, actualizar el Number requiere crear un nuevo Street con el nuevo Number, luego un nuevo Address con el nuevo Street y, por último, un nuevo Person. ¿Ya te confundiste?

Una solución para este problema es usar lentes.

Implementa varias funciones de acceso a registros usando lentes. La suite de pruebas también te permite prescindir de las lentes por completo, para que puedas experimentar con distintos enfoques.

Los 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, considera 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 se necesitan lentes! Dicho esto, aunque los lentes son poco comunes en Roc, sí son comunes en otros lenguajes como Haskell y Scala, así que quizás tengas 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 un 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. whole normalmente es un registro, mientras que part puede ser cualquier tipo de campo. El campo get contiene una función que devuelve un part específico del whole dado, mientras que el campo set contiene una función que devuelve una copia del whole dado, pero con un part específico reemplazado por el part dado.

Por ejemplo, aquí hay un lente para obtener o establecer el cabello de una persona:

hair_lens = {
	get: |person| person.hair,
	set: |person, hair| { ..person, hair },
}

Podemos usar este lente para enfocarnos en el cabello de Bob, así:

bob_hair = bob |> hair_lens.get

Y podemos cambiar su cabello así:

new_hair = { ..bob.hair, length: Short }
new_bob = bob |> (hair_lens.set)(new_hair)

Nota: los paréntesis alrededor de hair_lens.set son obligatorios: sin ellos, Roc buscaría una función llamada set en el tipo de hair_lens.

Los lentes se vuelven especialmente útiles cuando empiezas a componerlos, lo que te permite obtener y establecer partes profundamente anidadas. Esto se puede hacer implementando una función como esta:

compose : Lens(outer, inner), Lens(inner, part) -> Lens(outer, part)

Una vez que esta función esté implementada, puedes usarla para crear un lente de longitud de cabello como este:

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 es posible 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, las pruebas verificarán que tu código pueda modificar varias 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 las pruebas usando la sintaxis de actualización de registros de Roc y que después intentes usar los lentes.

Editar en GitHub El enlace se abre en una ventana o una pestaña nuevas
Roc Exercism

¿Todo listo para empezar Persona lente?

Regístrate en Exercism para aprender y dominar Roc con 125 ejercicios y mentoría humana real, todo gratis.