Usa le lenti per aggiornare i record annidati (specifico per i linguaggi con dati immutabili).
Aggiornare i campi di record annidati e immutabili è piuttosto fastidioso. Il codice per casi del genere è tanto macchinoso quanto profonda è la struttura. Se hai, per esempio, una Person che contiene un Address, che ha una Street, che ha un Number, per aggiornare il Number devi creare una nuova Street con il nuovo Number, poi un nuovo Address con la nuova Street e, infine, una nuova Person con il nuovo Address. Già confuso?
Una soluzione a questo problema è usare le lenti.
Implementa diverse funzioni che accedono ai record usando le lenti. La suite di test permette anche di evitare del tutto le lenti, così puoi sperimentare approcci diversi.
In Roc le lenti non si usano molto, perché la sintassi di aggiornamento dei record copre bene la maggior parte dei casi d'uso. Ad esempio, considera questo record annidato:
bob = { hair: { color: Brown, length: Long }, mouth: Smiling, height: 6.0 }
Ora tagliamo i capelli a Bob:
new_bob = { ..bob, hair: { ..bob.hair, length: Short } }
Non servono le lenti! Detto questo, anche se in Roc le lenti sono rare, sono comuni in altri linguaggi come Haskell e Scala, quindi potresti essere curioso di sapere come si potrebbero implementare in Roc. È anche un buon modo per esercitarsi con alcune funzionalità avanzate di Roc, come i tipi parametrizzati e i record che contengono funzioni. In effetti, ecco un modo per rappresentare una lente in Roc:
Lens(whole, part) := {
get : whole -> part,
set : whole, part -> whole,
}
Questo è un tipo parametrizzato: whole e part possono essere tipi qualsiasi. Di solito whole è un record, mentre part può essere qualsiasi tipo di campo. Il campo get contiene una funzione che restituisce una specifica part del whole dato, mentre il campo set contiene una funzione che restituisce una copia del whole dato, ma con una specifica part sostituita dalla part data.
Ad esempio, ecco una lente per ottenere o impostare i capelli di una persona:
hair_lens = {
get: |person| person.hair,
set: |person, hair| { ..person, hair },
}
Possiamo usare questa lente per concentrarci sui capelli di Bob, così:
bob_hair = bob |> hair_lens.get
E possiamo cambiargli i capelli così:
new_hair = { ..bob.hair, length: Short }
new_bob = bob |> (hair_lens.set)(new_hair)
Nota: le parentesi attorno a hair_lens.set sono obbligatorie: senza di esse, Roc cercherebbe una funzione chiamata set nel tipo di hair_lens.
Le lenti diventano particolarmente utili quando inizi a comporle: ti permettono di ottenere e impostare parti annidate in profondità. Lo si può fare implementando una funzione come questa:
compose : Lens(outer, inner), Lens(inner, part) -> Lens(outer, part)
Una volta implementata questa funzione, puoi usarla per creare una lente per la lunghezza dei capelli, così:
length_lens = {
get: |hair| hair.length,
set: |hair, length| { ..hair, length },
}
hair_length_lens = compose(hair_lens, length_lens)
Ora puoi tagliare di nuovo i capelli a Bob:
set_hair_length = hair_length_lens.set
new_bob = bob |> set_hair_length(Short)
Potresti anche voler implementare una funzione che ti permetta di applicare qualsiasi trasformazione a una parte annidata:
over : Lens(whole, part), whole, (part -> part) -> whole
Una volta implementata, puoi usare over così:
cut_hair = |current_length| match current_length {
Long => Short
Short => Bald
Bald => Bald
}
new_bob = hair_length_lens |> over(bob, cut_hair)
In questo esercizio, i test verificheranno che il codice riesca a modificare varie parti annidate del seguente record annidato:
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" },
}
Ti consigliamo di superare prima i test usando la sintassi di aggiornamento dei record di Roc, e poi di provare con le lenti.
Iscriviti a Exercism per imparare e padroneggiare Roc con 125 esercizi e il mentoring di persone reali, tutto gratis.