Kurzusok
/
Roc
Roc
/
Feladatok
/
Lencsés személy
Lencsés személy

Lencsés személy

Közepes

Utasítások

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.

Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg
Roc Exercism

Készen állsz elkezdeni a(z) Lencsés személy feladatot?

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.