A lencsékkel egymásba ágyazott rekordokat frissíthetsz (azokra a nyelvekre jellemző, amelyek változtathatatlan adatokkal dolgoznak).
Az egymásba ágyazott, változtathatatlan rekordok mezőinek frissítése elég bosszantó tud lenni. Az ilyen esetek kódja pont olyan nehézkes, amilyen mély maga a szerkezet. Ha van mondjuk egy Person, amely Address-t tartalmaz, abban egy Street, abban pedig egy Number, akkor a Number frissítéséhez először létre kell hoznod egy új Street-t, amely az új Number-t tartalmazza, majd egy új Address-t, amely az új Street-t tartalmazza, végül pedig egy új Person-t, amely az új Address-t tartalmazza. Már el is vesztetted a fonalat?
A probléma egyik megoldása a lenses használata.
Valósíts meg több függvényt, amelyek lencsékkel érik el a rekordokat. A tesztkészlet lehetővé teszi azt is, hogy teljesen elhagyd a lencséket, így más megközelítésekkel kísérletezhetsz.
A lencséket nem használják sok mindenre a Rocban, mert a rekordfrissítési szintaxis szépen lefedi a legtöbb felhasználási esetet. Vegyük például ezt az egymásba ágyazott rekordot:
bob = { hair: { color: Brown, length: Long }, mouth: Smiling, height: 6.0 }
Most pedig adjunk Bobnak egy hajvágást:
new_bob = { ..bob, hair: { ..bob.hair, length: Short } }
Lencsékre nincs szükség! Ennek ellenére, bár a lencsék ritkák a Rocban, más nyelvekben, például Haskellben és Scalában gyakoriak, ezért kíváncsi lehetsz rá, hogyan lehetne megvalósítani őket Rocban. Ez emellett jó módja annak is, hogy gyakorold néhány haladó Roc-lehetőséget, például a paraméterezett típusokat és a függvényeket tartalmazó rekordokat. Íme, így lehet ábrázolni egy lencsét Rocban:
Lens(whole, part) := {
get : whole -> part,
set : whole, part -> whole,
}
Ez egy paraméterezett típus: a whole és a part bármilyen típus lehet. A whole jellemzően egy rekord, a part viszont bármilyen mezőtípus lehet. A get mező egy olyan függvényt tartalmaz, amely visszaadja az adott whole egy konkrét part-ját, a set mező pedig egy olyan függvényt, amely az adott whole egy másolatát adja vissza, azzal a különbséggel, hogy egy konkrét part-ot a megadott part-ra cserél.
Például íme egy lencse, amellyel lekérheted vagy beállíthatod egy személy haját:
hair_lens = {
get: |person| person.hair,
set: |person, hair| { ..person, hair },
}
Ezzel a lencsével Bob hajára fókuszálhatunk, így:
bob_hair = bob |> hair_lens.get
És így megváltoztathatjuk a haját:
new_hair = { ..bob.hair, length: Short }
new_bob = bob |> (hair_lens.set)(new_hair)
Megjegyzés: a hair_lens.set körüli zárójelek kötelezőek: nélkülük a Roc egy set nevű függvényt keresne a hair_lens típusában.
A lencsék különösen akkor válnak hasznossá, amikor elkezded őket komponálni, mert így mélyen egymásba ágyazott részeket is le tudsz kérdezni és be tudsz állítani. Ezt egy ilyen függvény megvalósításával érheted el:
compose : Lens(outer, inner), Lens(inner, part) -> Lens(outer, part)
Ha egyszer megvalósítottad ezt a függvényt, ezzel létrehozhatsz egy hajhossz-lencsét is, így:
length_lens = {
get: |hair| hair.length,
set: |hair, length| { ..hair, length },
}
hair_length_lens = compose(hair_lens, length_lens)
Most pedig adhatsz Bobnak még egy hajvágást:
set_hair_length = hair_length_lens.set
new_bob = bob |> set_hair_length(Short)
Az is lehet, hogy szeretnél megvalósítani egy olyan függvényt, amellyel bármilyen átalakítást alkalmazhatsz egy egymásba ágyazott részre:
over : Lens(whole, part), whole, (part -> part) -> whole
Ha megvalósítottad, így használhatod az over függvényt:
cut_hair = |current_length| match current_length {
Long => Short
Short => Bald
Bald => Bald
}
new_bob = hair_length_lens |> over(bob, cut_hair)
Ebben a feladatban a tesztek azt ellenőrzik majd, hogy a kódod képes-e módosítani a következő egymásba ágyazott rekord különféle beágyazott részeit:
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" },
}
Azt javasoljuk, hogy először a Roc rekordfrissítési szintaxisával menj át a teszteken, aztán próbálkozz inkább lencsékkel.
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) Roc nyelvet 125 feladat segítségével, valódi emberi mentorálással, mindez ingyen.