Διαδρομές
/
Roc
Roc
/
Ασκήσεις
/
Άνθρωπος με φακό
Άνθρωπος με φακό

Άνθρωπος με φακό

Μέτριο

Οδηγίες

Χρησιμοποίησε lenses για να ενημερώσεις εμφωλευμένες καταγραφές (αφορά γλώσσες με αμετάβλητα δεδομένα).

Η ενημέρωση πεδίων εμφωλευμένων, αμετάβλητων καταγραφών είναι κάπως ενοχλητική. Ο κώδικας για τέτοιες περιπτώσεις είναι τόσο δυσκίνητος όσο βαθιά είναι η δομή. Αν έχεις, ας πούμε, ένα Person που περιέχει ένα Address, το οποίο έχει ένα Street, το οποίο έχει ένα Number, τότε για να ενημερώσεις το Number χρειάζεται να δημιουργήσεις ένα νέο Street με το νέο Number, μετά ένα νέο Address με το νέο Street και, τέλος, ένα νέο Person με το νέο Address. Μπερδεύτηκες ήδη;

Μια λύση σε αυτό το πρόβλημα είναι να χρησιμοποιήσεις lenses.

Υλοποίησε αρκετές συναρτήσεις πρόσβασης καταγραφών χρησιμοποιώντας lenses. Η σουίτα δοκιμών σου επιτρέπει επίσης να αποφύγεις εντελώς τα lenses, ώστε να μπορέσεις να πειραματιστείς με διαφορετικές προσεγγίσεις.

Οι φακοί δεν χρησιμοποιούνται πολύ στη Roc, επειδή η σύνταξη ενημέρωσης καταγραφών καλύπτει ωραία τις περισσότερες περιπτώσεις χρήσης. Για παράδειγμα, σκέψου αυτή την εμφωλευμένη καταγραφή:

bob = { hair: { color: Brown, length: Long }, mouth: Smiling, height: 6.0 }

Ας κάνουμε τώρα ένα κούρεμα στον Bob:

new_bob = { ..bob, hair: { ..bob.hair, length: Short } }

Δεν χρειάζονται φακοί! Παρ' όλα αυτά, αν και οι φακοί είναι σπάνιοι στη Roc, είναι συνηθισμένοι σε άλλες γλώσσες όπως η Haskell και η Scala, οπότε ίσως αναρωτιέσαι πώς μπορεί κανείς να τους υλοποιήσει στη Roc. Είναι επίσης ένας καλός τρόπος να εξασκηθείς σε μερικές προχωρημένες δυνατότητες της Roc, όπως οι παραμετροποιημένοι τύποι και οι καταγραφές που περιέχουν συναρτήσεις. Πράγματι, να ένας τρόπος να αναπαραστήσεις έναν φακό στη Roc:

Lens(whole, part) := {
	get : whole -> part,
	set : whole, part -> whole,
}

Πρόκειται για έναν παραμετροποιημένο τύπο: το whole και το part μπορούν να είναι οποιοιδήποτε τύποι. Το whole είναι συνήθως μια καταγραφή, ενώ το part μπορεί να είναι οποιοσδήποτε τύπος πεδίου. Το πεδίο get περιέχει μια συνάρτηση που επιστρέφει ένα συγκεκριμένο part του δοσμένου whole, ενώ το πεδίο set περιέχει μια συνάρτηση που επιστρέφει ένα αντίγραφο του δοσμένου whole, με ένα συγκεκριμένο part να έχει αντικατασταθεί από το δοσμένο part.

Για παράδειγμα, να ένας φακός για να πάρεις ή να θέσεις τα μαλλιά ενός ατόμου:

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

Μπορούμε να χρησιμοποιήσουμε αυτόν τον φακό για να εστιάσουμε στα μαλλιά του Bob, έτσι:

bob_hair = bob |> hair_lens.get

Και μπορούμε να αλλάξουμε τα μαλλιά του έτσι:

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

Σημείωση: οι παρενθέσεις γύρω από το hair_lens.set είναι απαραίτητες: χωρίς αυτές, η Roc θα έψαχνε για μια συνάρτηση με το όνομα set στον τύπο του hair_lens.

Οι φακοί γίνονται ιδιαίτερα χρήσιμοι όταν αρχίζεις να τους συνθέτεις, επιτρέποντάς σου να παίρνεις και να θέτεις βαθιά εμφωλευμένα μέρη. Αυτό μπορεί να γίνει υλοποιώντας μια συνάρτηση σαν αυτή:

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

Μόλις υλοποιηθεί αυτή η συνάρτηση, μπορείς να τη χρησιμοποιήσεις για να δημιουργήσεις έναν φακό μήκους μαλλιών σαν αυτόν:

length_lens = {
	get: |hair| hair.length,
	set: |hair, length| { ..hair, length },
}
hair_length_lens = compose(hair_lens, length_lens)

Τώρα μπορείς να κάνεις στον Bob άλλο ένα κούρεμα:

set_hair_length = hair_length_lens.set
new_bob = bob |> set_hair_length(Short)

Μπορεί επίσης να θέλεις να υλοποιήσεις μια συνάρτηση που σου επιτρέπει να εφαρμόζεις οποιονδήποτε μετασχηματισμό σε ένα εμφωλευμένο μέρος:

over : Lens(whole, part), whole, (part -> part) -> whole

Μόλις την υλοποιήσεις, μπορείς να χρησιμοποιήσεις το over έτσι:

cut_hair = |current_length| match current_length {
	Long => Short
	Short => Bald
	Bald => Bald
}
new_bob = hair_length_lens |> over(bob, cut_hair)

Σε αυτή την άσκηση, τα τεστ θα ελέγξουν ότι ο κώδικάς σου μπορεί να τροποποιήσει διάφορα εμφωλευμένα μέρη της παρακάτω εμφωλευμένης καταγραφής:

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" },
}

Σου προτείνουμε να περάσεις πρώτα τα τεστ χρησιμοποιώντας τη σύνταξη ενημέρωσης καταγραφών της Roc και μετά να δοκιμάσεις αντ' αυτού να χρησιμοποιήσεις φακούς.

Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα
Roc Exercism

Έτοιμος να ξεκινήσεις την άσκηση Άνθρωπος με φακό;

Γράψου στο Exercism για να μάθεις και να κατακτήσεις Roc με 125 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.