Διαδρομές
/
Common Lisp
Common Lisp
/
Ασκήσεις
/
Το κλειδί της σύγκρισης
Το κλειδί της σύγκρισης

Το κλειδί της σύγκρισης

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

Εισαγωγή

Ισότητα

Η Common Lisp έχει πολλά διαφορετικά κατηγορήματα ισότητας. Αυτό διαφέρει από άλλες γλώσσες προγραμματισμού, οι οποίες μπορεί να έχουν μόνο ένα ή δύο (για παράδειγμα == και ===). Μερικά από αυτά τα κατηγορήματα στην Common Lisp είναι ειδικά για συγκεκριμένους τύπους, ενώ άλλα είναι γενικά. Με αυτά τα τελευταία θα ασχοληθούμε εδώ.

Υπάρχουν τέσσερα γενικά κατηγορήματα ισότητας και διαφέρουν ως προς το πόσο περιοριστικά είναι σε αυτό που θεωρούν "ίσο". Είναι, με σειρά από το πιο περιοριστικό στο λιγότερο περιοριστικό: eq, eql, equal και equalp.

Ένας σύντομος κατάλογος ορισμών (παραλείποντας μερικές λεπτομέρειες) είναι ο εξής:

  • eq: ορίζει την ισότητα ως το ότι τα δύο αντικείμενα είναι ταυτόσημα. π.χ.:
(eq 'a 'a)                 ; => T
(eq (list 1 2) (list 1 2)) ; => NIL
  • eql: ορίζει την ισότητα ως εξής: δύο αριθμοί με τον ίδιο τύπο και την ίδια τιμή, δύο χαρακτήρες που είναι ίδιοι, ή, για οτιδήποτε άλλο, αν είναι eq. π.χ.:
(eql 1 1)     ; => T
(eql #\a #\a) ; => T
(eql 1 1.0)   ; => NIL
(eql #\a #\A) ; => NIL
  • equal: ορίζει την ισότητα ως εξής: δύο λίστες είναι equal αν κάθε στοιχείο τους είναι επίσης equal· δύο συμβολοσειρές είναι equal αν κάθε στοιχείο τους είναι eql· δύο πίνακες είναι equal αν είναι eq· οτιδήποτε άλλο είναι equal αν είναι eql. π.χ.:
(equal (list 1 2) (list 1 2)) ; => T
(equal #(1 2) #(1 2))         ; => NIL
(equal "foo" "foo")           ; => T
  • equalp: ορίζει την ισότητα ως εξής: οι συμβολοσειρές και οι χαρακτήρες συγκρίνονται χωρίς διάκριση πεζών-κεφαλαίων· οι αριθμοί συγκρίνονται με κάποια μετατροπή τύπου· οι λίστες και οι πίνακες είναι equalp αν κάθε στοιχείο τους είναι επίσης equalp, οι δομές αν είναι του ίδιου τύπου και όλες οι υποδοχές τους είναι equalp, και οι πίνακες κατακερματισμού αν τα κλειδιά και οι τιμές τους είναι equalp π.χ.:
(equalp "foo" "FoO")                          ; => T
(equalp 3 3.0)                                ; => T
(equalp (make-a-structure :slot1 1 :slot2 2) 
        (make-a-structure :slot1 1 :slot2 2)) ; => T

Οδηγίες

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

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

Κάθε τεστ αντιπροσωπεύει έναν λαβύρινθο και κάθε assertion είναι ένα δωμάτιο. Θα χρειαστεί να γράψεις συναρτήσεις κατηγορήματα που αποτιμώνται σε T όταν τα ορίσματα είναι ίσα και σε NIL όταν δεν είναι.

1. Ο λαβύρινθος της ισότητας των αντικειμένων

Αυτός ο λαβύρινθος έχει μόνο ένα δωμάτιο. Πρέπει να παρέχεις μια συνάρτηση που να μπορεί να πει αν δύο αντικείμενα είναι το ίδιο αντικείμενο.

Για παράδειγμα:

a                         ; => "pizza"
b                         ; => "pizza"

(key-object-identity a a) ; => T
(key-object-identity a b) ; => NIL

γιατί ενώ τα a και b φαίνεται να είναι τα ίδια, δεν είναι το ίδιο αντικείμενο.

2. Ο λαβύρινθος των αριθμών

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

Για παράδειγμα:

a                                    ; => 13
b                                    ; => 13.0
c                                    ; => 13

(key-numbers a b)                    ; => NIL
(key-numbers a c)                    ; => T
(key-numbers-of-different-types a b) ; => T

γιατί ενώ τα a και b είναι αριθμητικά ίσα, είναι διαφορετικών τύπων.

3. Ο λαβύρινθος των χαρακτήρων

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

Για παράδειγμα:

a                                       ; => #\X
b                                       ; => #\x
c                                       ; => #\X

(key-characters a b)                    ; => NIL
(key-characters a c)                    ; => T
(key-characters-case-insensitively a b) ; => T

γιατί μόνο οι πολύ επιεικείς συναρτήσεις κατηγορήματα ισότητας αγνοούν τα πεζά-κεφαλαία κατά τη σύγκριση δύο χαρακτήρων.

4. Ο λαβύρινθος των συμβολοσειρών

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

Για παράδειγμα:

a                                    ; => "pizza"
b                                    ; => "PIZZA"
c                                    ; => "pizza"

(key-strings a b)                    ; => NIL
(key-strings a c)                    ; => T
(key-strings-case-insensitively a b) ; => T

γιατί μόνο οι πολύ επιεικείς συναρτήσεις κατηγορήματα ισότητας αγνοούν τα πεζά-κεφαλαία κατά τη σύγκριση δύο συμβολοσειρών.

5. Ο λαβύρινθος των cons

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

Για παράδειγμα:

syms-a                                     ; => (left . right)
syms-b                                     ; => (up . down)
syms-c                                     ; => (left . right)
chars-a                                    ; => (#\x . #\y)
chars-b                                    ; => (#\x . #\Y)
chars-c                                    ; => (#\x . #\y)
nums-a                                     ; => (13 . 23)
nums-b                                     ; => (13 . 23.0)
nums-c                                     ; => (13 . 23)


(key-conses-of-symbols syms-a syms-b)      ; => NIL
(key-conses-of-symbols syms-a syms-c)      ; => T

(key-conses-of-characters chars-a chars-b) ; => NIL
(key-conses-of-characters chars-a chars-c) ; => T
(key-conses-of-characters-case-insensitively 
  chars-a chars-b)                         ; => T

(key-conses-of-numbers nums-a nums-b)      ; => NIL
(key-conses-of-numbers nums-a nums-c)      ; => T
(key-conses-of-numbers-of-different-types 
  nums-a nums-b)                           ; => T

γιατί ακόμα και με ένα κατηγόρημα ισότητας που κοιτάζει μέσα σε ένα cons, μπορεί να μην είναι αρκετά επιεικές ώστε να αγνοεί τα πεζά-κεφαλαία ή τον αριθμητικό τύπο κατά τη σύγκριση.

6. Ο λαβύρινθος των πινάκων

Αυτός ο λαβύρινθος είναι πιο απλός, με μόνο δύο δωμάτια. Το πρώτο χρειάζεται ένα κλειδί που ελέγχει αν οι πίνακες είναι οι ίδιοι πίνακες. Το δεύτερο χρειάζεται ένα κλειδί που θα ελέγχει τα περιεχόμενα των πινάκων.

Για παράδειγμα:

a                        ; => #[13 23]
b                        ; => #[13 23]
c                        ; => #[13 23.0]

(key-arrays a b)         ; => NIL
(key-arrays a c)         ; => NIL
(key-arrays-loosely a b) ; => T
(key-arrays-loosely a c) ; => T

γιατί μόνο οι πολύ επιεικείς ελεγκτές ισότητας θα ελέγξουν αν τα περιεχόμενα του πίνακα είναι ίσα.

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

Έτοιμος να ξεκινήσεις την άσκηση Το κλειδί της σύγκρισης;

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