format
Η Common Lisp έχει την έννοια του Εκτυπωτή, που περιλαμβάνει όλες τις συναρτήσεις για τη γραφή κειμενικών αναπαραστάσεων των δεδομένων της Lisp. Μία τέτοια συνάρτηση είναι η format, η οποία επιτρέπει στον προγραμματιστή να μορφοποιήσει τα δεδομένα όπως θέλει.
Οι δυνατότητες της format και του Εκτυπωτή της Lisp γενικότερα είναι ένα μεγάλο θέμα. Εδώ θα δούμε τα βασικά της χρήσης της format.
Η συνάρτηση format δέχεται τουλάχιστον δύο ορίσματα: μια ροή στην οποία θα γίνει η εκτύπωση και μια συμβολοσειρά ελέγχου που ορίζει τι και πώς θα εκτυπωθεί.
Οι ροές είναι μια ξεχωριστή έννοια και θα περιγραφούν αλλού. Για την ώρα, το μόνο που χρειάζεται να ξέρεις είναι ότι η εκτύπωση γίνεται στη ροή και ότι υπάρχουν δύο ειδικές τιμές για αυτό το όρισμα: t και nil. Το t σημαίνει να γίνει εκτύπωση στην τυπική έξοδο (στην πραγματικότητα, στη ροή στην οποία είναι δεσμευμένη η μεταβλητή *standard-output*), και το nil σημαίνει να δημιουργηθεί μια συμβολοσειρά και να επιστραφεί.
Σημείωσε ότι η format θα αποτιμάται πάντα σε nil, εκτός από τη δεύτερη περίπτωση, όπου το nil ορίζεται ως ροή. Αυτός είναι ένας συνηθισμένος τρόπος για απλή παρεμβολή ή κατασκευή συμβολοσειρών.
(format nil "hello world") ; => "hello world"
(format t "hello world") ; => NIL (but "hello world" is printed to standard output)
Η συμβολοσειρά ελέγχου μπορεί να περιέχει "οδηγίες μορφοποίησης", που καθορίζουν στην format τι θα εκτυπωθεί και πώς θα ερμηνευτούν τυχόν άλλες παράμετροι που της περνάς. Κατά μία έννοια, η συμβολοσειρά ελέγχου είναι ένα πρόγραμμα το οποίο η format θα ερμηνεύσει και θα εκτελέσει. Όλες οι οδηγίες ξεκινούν με ~ και ακολουθούνται από έναν χαρακτήρα (π.χ. ~A, ~D, ~&). Ο χαρακτήρας δεν έχει σημασία αν είναι κεφαλαίος ή πεζός.
Οι περισσότερες οδηγίες μορφοποίησης απλώς παρεμβάλλουν ένα όρισμα της format στην έξοδο. Λέμε ότι "καταναλώνουν" το όρισμα. Κάποιες οδηγίες δεν καταναλώνουν ορίσματα, ή καταναλώνουν περισσότερα από ένα. Μία οδηγία μάλιστα σου επιτρέπει να μεταπηδάς μέσα στη λίστα ορισμάτων ή να παραλείπεις ορίσματα.
Μια πολύ γενικής χρήσης οδηγία μορφοποίησης είναι η ~A. Αυτή εκτυπώνει μια 'αναγνώσιμη από άνθρωπο' εκδοχή των δεδομένων.
(format nil "Value = ~a" 10) ; => "10"
(format nil "hello ~a" "world") ; => "hello world"
(format nil "The list is: ~A" (list 1 2 3)) ; => "The list is: (1 2 3)"
Μια άλλη χρήσιμη οδηγία μορφοποίησης είναι η ~S. Αυτή εκτυπώνει μια 'αναγνώσιμη από μηχανή' εκδοχή των δεδομένων. Αυτό μπορεί να είναι πολύ χρήσιμο αν θέλεις να μπορείς να ερμηνεύσεις την έξοδο που δημιουργήθηκε ως δεδομένα Lisp. Για πολλά πράγματα θα φαίνεται ίδια με την ~A, αλλά πρόσεξε ότι για τις συμβολοσειρές, για παράδειγμα, η έξοδος θα περιλαμβάνει τα εισαγωγικά (με διαφυγή όταν βρίσκονται μέσα σε άλλη συμβολοσειρά), ώστε η τιμή να μπορεί να διαβαστεί ξανά ως η παράμετρος συμβολοσειράς.
(format nil "~s" 10) ; => "10"
(format nil "~s" "hello world") ; => "\"hello world\""
(format nil "~s" (list 1 2 3)) ; => "(1 2 3)"
Δύο ακόμη πολύ χρήσιμες οδηγίες είναι οι ~% και ~&. Η πρώτη βγάζει έναν χαρακτήρα αλλαγής γραμμής, ενώ η δεύτερη βγάζει μια "φρέσκια γραμμή". Η διαφορά είναι ότι η ~% βγάζει πάντα μια αλλαγή γραμμής, ενώ η ~& θα βγάλει μία μόνο αν δεν βρίσκεται ήδη στην αρχή μιας γραμμής. Καμία από τις δύο δεν καταναλώνει όρισμα.
(format nil "~%new~%lines") ; => "
new
lines"
(format nil "~&new~&lines" ; => "new
lines"
Τέλος, το ~~ είναι μια απλή οδηγία που βγάζει ένα κυριολεκτικό ~.
Όπως σχεδόν κάθε άνθρωπος που έχει δουλειά, έτσι κι η Λέιλα, το Lisp Alien, χρειάζεται μερικές φορές να φτιάχνει αναφορές για να ενημερώνει τους άλλους. Σου ζητάει να τη βοηθήσεις να μορφοποιήσει τα δεδομένα που έχει για αυτές τις αναφορές.
Το πρώτο πράγμα που χρειάζεται η Λέιλα είναι μια συνάρτηση: η format-quarter-value, που παίρνει δύο παραμέτρους: το ημερολογιακό τρίμηνο και την τιμή, και τη μορφοποιεί για μια αναφορά. Πρέπει να αξιολογείται σε μια συμβολοσειρά.
(format-quarter-value "last" 3.14) ; => "The value last quarter: 3.14"
(format-quarter-value "this" 0) ; => "The value this quarter: 0"
Η Λέιλα σε ευχαριστεί για τη συνάρτηση format-quarter-value και λέει ότι θα της φανεί πολύ χρήσιμη στην επόμενη συνάρτηση που χρειάζεται.
Η επόμενη αναφορά πρέπει να δείχνει το τρίμηνο και την τιμή από 2 τρίμηνα, τυπωμένα σε δύο γραμμές.
Επίσης, η έξοδος πρέπει να πηγαίνει στο stream που δίνεται ως πρώτο όρισμα.
Για παράδειγμα: το (format-two-quarters t "last" 3.14 "this" 0) θα παράγει τα εξής στην τυπική έξοδο:
The value last quarter: 3.14
The value this quarter: 0
Πρόσεξε τις κενές γραμμές γύρω του.
Η Λέιλα ξέχασε να σου πει ότι στους Lisp Aliens αρέσει να βλέπουν τις τιμές με τρόπο που να είναι αναγνώσιμος ως δεδομένα Lisp. Έτσι, χρειάζονται μια νέα συνάρτηση που να μπορεί να διαβαστεί ως δεδομένα Lisp (και πάλι στο συγκεκριμένο stream):
(format-two-quarters-for-reading nil "last" 3.14 "this" 0) ; =>
"(\"The value last quarter: 3.14\" \"The value this quarter: 0\")"
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Common Lisp με 27 έννοιες92 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.