Διαδρομές
/
Elm
Elm
/
Ασκήσεις
/
Ασφαλές σεντούκι θησαυρού
Ασφαλές σεντούκι θησαυρού

Ασφαλές σεντούκι θησαυρού

Άσκηση εκμάθησης

Εισαγωγή

Αδιαφανείς τύποι

Εισαγωγή

Οι αδιαφανείς τύποι είναι μια τεχνική ενθυλάκωσης στην Elm. Μερικοί την αποκαλούν και απόκρυψη πληροφορίας, ή απόκρυψη λεπτομερειών υλοποίησης. Χρησιμοποιούνται επίσης συχνά για την επιβολή επικύρωσης, με το μοτίβο Parse, dont validate. Για παράδειγμα, θα μπορούσες να έχεις έναν αδιαφανή τύπο EmailAddress, που μπορεί να περιέχει μόνο έγκυρες διευθύνσεις email (σε αντίθεση με μια String, που μπορεί να περιέχει οτιδήποτε).

Δημιουργία αδιαφανούς τύπου

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

type Maybe a
    = Nothing --> Variant implies a 'Nothing' function, with type 'Maybe a', and destructuring of 'Nothing'
    | Just a  --> Variant implies a 'Just' function, with type 'a -> Maybe a', and destructuring of 'Just _'

Από προεπιλογή, όλα αυτά είναι εσωτερικά στο αρχείο / στο module, και χρησιμοποιούμε τη λέξη-κλειδί exposing για να επιλέξουμε τι θα εξάγουμε. Για να δημιουργήσεις έναν αδιαφανή τύπο, απλώς επιλέγεις να μην εξάγεις τις παραλλαγές.

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

Parse, don't validate

Ίσως η πιο συνηθισμένη χρήση των αδιαφανών τύπων είναι η επιβολή επικύρωσης, με το μοτίβο Parse, dont validate. Σε αυτό το μοτίβο, εκθέτεις μια συνάρτηση που δέχεται μια είσοδο με λιγότερη δομή / ασφάλεια τύπων από ό,τι θέλεις, όπως μια String, και μετά κάνεις parse αυτή την είσοδο σε έναν πιο δομημένο τύπο, όπως EmailAddress, είτε επιστρέφοντας τον τύπο, είτε επιστρέφοντας ένα σφάλμα (συνήθως Maybe ή Result).

Για παράδειγμα, στον παρακάτω κώδικα, τα εξωτερικά module μπορούν να δημιουργήσουν έναν τύπο EmailAddress μόνο μέσω της συνάρτησης parseEmailAddress, οπότε όταν δουλεύεις με τον τύπο EmailAddress, είσαι σίγουρος ότι είναι έγκυρος.

module EmailAddress exposing ( EmailAddress, parseEmailAddress, getEmailAddress )

-- The `EmailAddress` custom type has one variant, also called `EmailAddress`
-- When a custom type has one variant, it is idiomatic to use the same name for both.
type EmailAddress = 
  EmailAddress String

-- create an EmailAddress variant
parseEmailAddress: String -> Maybe EmailAddress
parseEmailAddress candidateEmailAddress =   
  if isValidEmailAddress candidateEmailAddress then
    Just (EmailAddress candidateEmailAddress)
  else
    Nothing

-- get an EmailAddress variant
getEmailAddress: EmailAddress -> String
getEmailAddress ( EmailAddress  emailAdress ) =
  emailAdress

isValidEmailAddress: String -> bool
-- ... 

Οδηγίες

Σε αυτή την άσκηση θα γράψεις ένα γενικό (ή μαγικό!) SecureTreasureChest, για να αποθηκεύεις κάποιον θησαυρό. Οι πιο παρατηρητικοί θα έχουν προσέξει ότι το προηγούμενο TreasureChest δεν ήταν και τόσο ασφαλές! Αν χρησιμοποιούσες τη συνάρτηση getTreasure, έπρεπε να δώσεις τον κωδικό πρόσβασης, αλλά μπορούσες ακόμα απλώς να αποδομήσεις τον τύπο TreasureChest για να πάρεις τον θησαυρό, χωρίς να χρειάζεται να ξέρεις τον κωδικό πρόσβασης. Ακόμα χειρότερα, μπορούσες να ανακτήσεις με τον ίδιο τρόπο ακόμα και τον κωδικό πρόσβασης! Ας το διορθώσουμε αυτό χρησιμοποιώντας έναν αδιαφανή τύπο.

1. Όρισε τον αδιαφανή τύπο Password, χρησιμοποιώντας το μοτίβο "Parse, don't validate"

Όρισε έναν προσαρμοσμένο τύπο Password με μία μόνο παραλλαγή.

Η παραλλαγή θα πρέπει να έχει μια συσχετισμένη τιμή String, για τον κωδικό πρόσβασης.

Θα πρέπει να εκθέσεις τον τύπο Password, αλλά όχι την παραλλαγή. Αυτό κάνει το Password έναν αδιαφανή τύπο και σημαίνει ότι δεν μπορείς πλέον να χρησιμοποιήσεις αποδόμηση για να πάρεις τον κωδικό πρόσβασης. Δεν είναι δυνατό να ελέγξεις αν ένας τύπος είναι αδιαφανής ή όχι· σε κώδικα παραγωγής, θα χρησιμοποιούσες το elm-review (ένα εργαλείο στατικής ανάλυσης) για να το επιβάλεις.

Όρισε και έκθεσε μια συνάρτηση createPassword, με ορισμό τύπου, που δέχεται ένα String και επιστρέφει ένα Maybe Password.

Το Owasp συνιστά οι κωδικοί πρόσβασης να έχουν τουλάχιστον 8 χαρακτήρες, οπότε ας χρησιμοποιήσουμε το μοτίβο Parse, don't validate για να επιβάλουμε αυτή την αναλλοίωτη συνθήκη.

Αν ο κωδικός πρόσβασης έχει λιγότερους από 8 χαρακτήρες, η createPassword θα πρέπει να επιστρέφει Nothing, αλλιώς θα πρέπει να επιστρέφει Just Password.

2. Έκθεσε το SecureTreasureChest, αλλά όχι την παραλλαγή του

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

3. Όρισε τη συνάρτηση createTreasure

Αυτή η συνάρτηση θα πρέπει να δέχεται δύο παραμέτρους και να έχει ορισμό τύπου.

  • έναν γενικό τύπο (για τον θησαυρό)
  • ένα Password (για τον κωδικό πρόσβασης)

Η συνάρτηση θα πρέπει να επιστρέφει ένα SecureTreasureChest.

Έκθεσε αυτή τη συνάρτηση, ώστε άλλα modules να μπορούν να δημιουργούν στιγμιότυπα του SecureTreasureChest.

4. Όρισε τη συνάρτηση getTreasure

Αυτή η συνάρτηση θα πρέπει να δέχεται δύο παραμέτρους και να έχει ορισμό τύπου.

  • ένα String (για τον κωδικό πρόσβασης)
  • έναν γενικό προσαρμοσμένο τύπο SecureTreasureChest

Αυτή η συνάρτηση θα πρέπει να συγκρίνει τον κωδικό πρόσβασης που δίνεται με το Password του SecureTreasureChest.

Η συνάρτηση θα πρέπει να επιστρέφει ένα Maybe.

Αν οι κωδικοί πρόσβασης ταιριάζουν, τότε επέστρεψε Just με τη γενική τιμή από το SecureTreasureChest (τον θησαυρό!)

Αν οι κωδικοί πρόσβασης δεν ταιριάζουν, τότε επέστρεψε Nothing.

Έκθεσε αυτή τη συνάρτηση, ώστε άλλα modules να μπορούν να πάρουν τον θησαυρό από ένα SecureTreasureChest, αρκεί να δίνουν τον σωστό κωδικό πρόσβασης.

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

Έτοιμος να ξεκινήσεις την άσκηση Ασφαλές σεντούκι θησαυρού;

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