Εισαγωγή
Γεια σε όλους! Ελπίζω να πάνε όλα καλά.
Οι τελευταίες εβδομάδες στο Exercism ήταν πραγματικά συναρπαστικές, με την κυκλοφορία του Exercism Premium και του Exercism Insiders. Είχαμε επίσης μερικές εξαιρετικές συναντήσεις της κοινότητας, και πολλές βελτιώσεις του site έχουν ήδη αναπτυχθεί ή έρχονται σύντομα. Υπάρχουν πολλά για να ενθουσιαστείς αυτή τη στιγμή, αλλά τίποτα πιο συναρπαστικό από την είσοδό μας στον 6ο μήνα του #12in23! - Το καλοκαίρι των S-expressions, ή πιο κομψά, το Summer of Sexps.
Ως συνήθως, μαζί μου είναι ο σοφός γκουρού του κόσμου του προγραμματισμού, ο Erik.
Έχουμε λοιπόν πέντε γλώσσες αυτόν τον μήνα: Clojure, Common Lisp, Emacs Lisp, Racket και Scheme. Κάθε μία από αυτές τις γλώσσες είναι διάλεκτος της Lisp, και έτσι, αντί να εστιάσουμε υπερβολικά στις διαφορετικές γλώσσες σε αυτό το βίντεο, θα δούμε λίγο περισσότερο την ίδια τη Lisp και τι την κάνει ξεχωριστή. Και θα τελειώσουμε με μια σύντομη επισκόπηση των γλωσσών.
Αλλά πριν από αυτό, λίγες πρακτικές λεπτομέρειες! Για να πάρεις το badge του Summer of Sexps, πρέπει να ολοκληρώσεις οποιεσδήποτε πέντε ασκήσεις σε μία από αυτές τις γλώσσες μέσα στον Ιούνιο.
Τα badges
Υπάρχει επίσης το badge 12in23, που διαρκεί όλο τον χρόνο. Για να το πάρεις, πρέπει να λύσεις πέντε από τις επιλεγμένες ασκήσεις στη γλώσσα. Αν το βλέπεις αυτό μετά τον Ιούνιο, μπορείς να το κάνεις οποιαδήποτε στιγμή μέσα στη χρονιά, οπότε δεν έχεις χάσει τίποτα. Επειδή πολλοί μπορεί να μην έχουν δουλέψει ποτέ με Lisp, προσπαθήσαμε να επιλέξουμε σχετικά απλές ασκήσεις που σου δίνουν μια πρώτη γεύση από το πώς μοιάζει μια γλώσσα Lisp.
- Leap: δουλεύεις με συνθήκες Boolean και truthiness (και προαιρετικά, λεξική εμβέλεια)
- Two-Fer: μορφοποιείς μια συμβολοσειρά και δουλεύεις με μια προαιρετική παράμετρο
- Difference of Squares: καλείς συναρτήσεις που ορίζει ο χρήστης και κάνεις μαθηματικά σε προθηματική σημειογραφία
- Robot Name: δουλεύεις με τυχαιότητα, atoms και δομημένα δεδομένα
- Matching Brackets: χρησιμοποιείς αναδρομή για να επικυρώσεις μια συμβολοσειρά
Αυτές οι ασκήσεις και εκείνες των προηγούμενων μηνών βρίσκονται όλες στη σελίδα του #12in23.
Επισκόπηση
Λοιπόν, γλώσσες βασισμένες στη Lisp. Υποθέτω πως πρέπει να ξεκινήσουμε κατανοώντας λίγο την ίδια τη Lisp. Ας ξεκινήσουμε με μια μικρή εισαγωγή στη Lisp γενικά.
Lisp
-
Το πρώτο πράγμα που πρέπει να σημειώσεις είναι ότι η Lisp είναι μία από τις παλαιότερες γλώσσες.
-
Δημιουργήθηκε από τον John McCarthy στο MIT το 1958, τότε που οι υπολογιστές καταλάμβαναν ακόμα ολόκληρα δωμάτια από πάνω μέχρι κάτω 🙂
-
Το όνομα Lisp σημαίνει LISt Processing (ή LISt Processor), αναδεικνύοντας τη σημασία της δομής δεδομένων λίστα.
-
Σχεδιάστηκε με σκοπό την έρευνα στην τεχνητή νοημοσύνη.
-
Η Lisp βασίστηκε στον λογισμό λάμβδα, που επινόησε ο Alonzo Church, ένα τυπικό σύστημα για την περιγραφή του υπολογισμού στα μαθηματικά (απλοποιημένα).
-
Είναι μια γλώσσα απίστευτα επιδραστική, για διάφορους λόγους:
-
Είναι η δεύτερη παλαιότερη γλώσσα προγραμματισμού υψηλού επιπέδου που χρησιμοποιείται ακόμα ευρέως (μετά τη Fortran)
-
Ήταν η πρώτη γλώσσα συναρτησιακού προγραμματισμού υψηλού επιπέδου και εισήγαγε πολλά από τα χαρακτηριστικά που σήμερα συνδέουμε με τον συναρτησιακό προγραμματισμό.
-
Σημείωσε ότι η Lisp υποστήριζε επίσης τον προστακτικό προγραμματισμό
-
Ήταν η πρώτη γλώσσα με garbage collector, απαλλάσσοντας τον προγραμματιστή από τη χειροκίνητη διαχείριση μνήμης
-
Η σχετικά μικρή σύνταξη και η σχετικά απλή σημασιολογία της την κάνουν ιδανική για εκπαιδευτικούς σκοπούς.
-
Η Lisp (ή καλύτερα: μία από τις διαλέκτους της) χρησιμοποιείται γι' αυτό συχνά για τη διδασκαλία του προγραμματισμού
-
Έχει γεννήσει (και συνεχίζει να γεννά!) πάρα πολλές διαλέκτους (από τις οποίες θα συζητήσουμε όσες υποστηρίζονται στο Exercism).
-
Με άλλα λόγια, στο δέντρο των γλωσσών προγραμματισμού υπάρχει ξεχωριστός κλάδος για τις γλώσσες τύπου Lisp (όπως ακριβώς υπάρχει κλάδος για τις γλώσσες τύπου C).
Όταν μίλησα πρόσφατα με τον Simon Peyton Jones, έναν από τους δημιουργούς της Haskell, μιλούσε για τη διαφορά ανάμεσα σε γλώσσες χτισμένες γύρω από μηχανές Turing και σε γλώσσες χτισμένες γύρω από τον λογισμό λάμβδα. Αξίζει λοιπόν να δεις εκείνη τη συνέντευξη, αν θέλεις να μάθεις περισσότερα γι' αυτό.
Παρενθέσεις
Υπάρχουν πολλές παρενθέσεις στις Lisp, αλλά αυτό δεν είναι απαραίτητα κακό (όπως ακριβώς το να έχει πολλά άγκιστρα δεν είναι απαραίτητα κακό στις γλώσσες τύπου C). Οι Lisp βασίζονται γύρω από κάτι που ονομάζεται: S-expressions. Μια S-expression (συντόμευση του symbolic expression, με συντομογραφίες sexpr ή sexp, εξ ου και το όνομα της πρόκλησης αυτού του μήνα) είναι μια έκφραση που αναπαριστά δεδομένα. Επινοήθηκαν για την πρώτη γλώσσα Lisp και διαδόθηκαν από αυτήν. Μια S-expression μπορεί να πάρει μία από δύο μορφές:
- Ένα άτομο (π.χ. 'x'). Σκέψου τα ως μη εμφωλευμένες "τιμές" ή ως τα φύλλα του δέντρου
- Μια έκφραση x . y, όπου τα x και y είναι S-expressions. Σκέψου τις ως ζεύγη, όπου το y μπορεί να είναι το επόμενο στοιχείο της λίστας (αν υπάρχει) ή κόμβοι σε ένα δέντρο. Σημείωσε ότι αυτός είναι ένας αναδρομικός ορισμός, που τερματίζει στο επίπεδο των φύλλων. Συνήθως, για αυτόν τον τύπο S-expression χρησιμοποιούνται παρενθέσεις.
S-expressions
Οι S-expressions χρησιμοποιούνται στη Lisp για την αναπαράσταση τόσο δεδομένων όσο και λιστών. Επομένως, κάθε φορά που ορίζεις μια λίστα, θα χρησιμοποιείς παρενθέσεις. Αν το συνδυάσεις με το γεγονός ότι: η λίστα είναι η βασική δομή δεδομένων της Lisp (εξ ου και το όνομά της), σε κάποιες Lisp είναι η μόνη δομή δεδομένων, θα καταλήξεις με πάρα πολλές παρενθέσεις. Για να δεις πόσο κεντρικές είναι οι λίστες: αν θέλεις να καλέσεις μια συνάρτηση στη Lisp, το κάνεις δημιουργώντας μια λίστα.
Είναι ενδιαφέρον ότι το πρώτο στοιχείο της λίστας (γνωστό και ως head) αναπαριστά τη συνάρτηση που καλείται, και τα υπόλοιπα στοιχεία (γνωστά και ως tail) περνούν ως ορίσματα. Αυτό είναι γνωστό ως προθηματική σημειογραφία (όπου ο τελεστής έρχεται πριν από τα τελούμενα), που μπορεί να φαίνεται κάπως παράξενο στην αρχή, αλλά στην πραγματικότητα είναι πολύ χρήσιμο:
- Μπορείς να εφαρμόσεις έναν τελεστή σε πολλά ορίσματα χωρίς να χρειάζεται να τον επαναλάβεις (π.χ. (+ 1 2 3))
- Η προτεραιότητα των τελεστών γίνεται ρητή, αφού έτσι κι αλλιώς πρέπει να ορίσεις μια νέα S-expression για να καλέσεις διαφορετικό τελεστή
Είναι αρκετά ενδιαφέρον ότι οι λίστες χρησιμοποιούνται ακόμα και για την αναπαράσταση του πηγαίου κώδικα, αλλά θα επανέλθουμε σε αυτό αργότερα.
Γενικά, οι περισσότερες Lisp έχουν αρκετά μινιμαλιστική σύνταξη και σχετικά απλή σημασιολογία, κάτι που τις κάνει σχετικά εύκολες στην εκμάθηση, και η κατανόηση του κώδικα γίνεται επίσης ευκολότερη. Αυτή η μινιμαλιστική σύνταξη δεν τις κάνει λιγότερο ισχυρές! Ο συνδυασμός αυτών των δύο (μινιμαλιστική σύνταξη + απλή σημασιολογία) κάνει τις Lisp ιδανικές για τη συγγραφή μεταγλωττιστών και διερμηνευτών. Αν ποτέ θελήσεις να φτιάξεις τον δικό σου μεταγλωττιστή, το να φτιάξεις μια Lisp είναι καλή επιλογή!
Κουλ χαρακτηριστικά της Lisp
Όπως αναφέρθηκε πριν, οι Lisp χρησιμοποιούν τους ίδιους τύπους και δομές δεδομένων εσωτερικά για την αναπαράσταση του κώδικα. Αυτή η ιδιότητα ονομάζεται homoiconicity (ή homoiconic). Με άλλα λόγια, μια γλώσσα είναι homoiconic αν ένα πρόγραμμα γραμμένο σε αυτήν μπορεί να χειριστεί ως δεδομένα χρησιμοποιώντας την ίδια τη γλώσσα, και έτσι η εσωτερική αναπαράσταση του προγράμματος μπορεί να συναχθεί απλώς διαβάζοντας το ίδιο το πρόγραμμα. Αυτή η ιδιότητα συνοψίζεται συχνά λέγοντας ότι η γλώσσα αντιμετωπίζει τον κώδικα ως δεδομένα.
Γλώσσες
Scheme
- Δημιουργήθηκε τη δεκαετία του 1970 από τους Guy Steele και Gerald Sussman στο MIT AI Lab.
- Ξεκίνησε ως μια προσπάθεια να κατανοηθεί το μοντέλο Actor του Carl Hewitt μέσω ενός μικροσκοπικού διερμηνευτή Lisp.
- Η ίδια η γλώσσα παρουσιάστηκε σε μια σειρά από ερευνητικά σημειώματα (AI Memos) που έγιναν γνωστά συλλογικά ως τα Lambda Papers.
- Η πρώτη διάλεκτος Lisp που χρησιμοποίησε λεξική εμβέλεια (οι τιμές είναι ορατές μόνο εκεί που ορίζονται) και μία από τις πρώτες γλώσσες που υποστήριξε συνεχίσεις πρώτης τάξης.
- Επίσημο πρότυπο IEEE και ένα de facto πρότυπο, γνωστό ως Revised Report on the Algorithmic Language Scheme (RnRS).
- Πολλές υλοποιήσεις: ChezScheme, Guile (και οι δύο υποστηρίζονται στο Exercism), MIT/GNU Scheme και Racket
- Πολύ μινιμαλιστική γλώσσα, με λίγη σύνταξη, αλλά αυτό δεν ήταν σκόπιμο.
- Οι δημιουργοί προσπάθησαν να φτιάξουν κάτι περίπλοκο, αλλά κατέληξαν να σχεδιάσουν κάτι πολύ πιο απλό από ό,τι σκόπευαν
- Ορθή αναδρομή ουράς. Ο ιδιωματικός τρόπος για επανάληψη είναι μέσω αναδρομής.
- Η Scheme βελτιστοποιεί τις αναδρομικές κλήσεις ουράς ώστε να μην καταναλώνει χώρο στη στοίβα ή άλλους πόρους. Αυτό σημαίνει ότι η αναδρομή μπορεί να χρησιμοποιηθεί σε οσοδήποτε μεγάλα δεδομένα ή για οσοδήποτε μεγάλο υπολογισμό
- Ισχυροί αριθμητικοί τύποι δεδομένων, όπως ρητοί και μιγαδικοί αριθμοί
- Καθυστερημένη αξιολόγηση, κάτι σαν τα promises.
- Ισχυρό σύστημα μακροεντολών.
- Οι υγιείς μακροεντολές μειώνουν την πιθανότητα απρόσμενων αποτελεσμάτων κατά τον ορισμό μακροεντολών.
Common Lisp
- Η εργασία πάνω στη Common Lisp ξεκίνησε το 1981, μετά από πρωτοβουλία του διευθυντή της ARPA Bob Engelmore, για την ανάπτυξη μιας ενιαίας, κοινοτικά αποδεκτής πρότυπης διαλέκτου Lisp, επειδή οι διάφορες διάλεκτοι που χρησιμοποιούνταν ήταν συχνά ασύμβατες μεταξύ τους, που σήμαινε ότι ο κώδικας και η γνώση δεν μπορούσαν να μοιραστούν
- Το πρώτο πρότυπο δημοσιεύτηκε το 1984 και το τελικό το 1994 (πολύ σταθερή προδιαγραφή)
- Επειδή είναι πρότυπο, υπάρχουν διαφορετικές υλοποιήσεις του, όπως η Steel Bank Common Lisp (η προεπιλογή του Exercism) και η CLisp.
- Υπάρχουν επίσης εμπορικές υλοποιήσεις, όπως οι Allegro CL και LispWorks, καθώς και η ECL (Embeddable Common Lisp), που μπορεί να ενσωματωθεί σε προγράμματα C, και η ABCL, που τρέχει στην εικονική μηχανή Java.
- Ορίζεται από πρότυπο (ANSI INCITS 226-1994), οπότε κώδικας γραμμένος πριν από 30 χρόνια τρέχει ακόμα μια χαρά σήμερα
- Πλούσιο και επεκτάσιμο σύστημα τύπων
- Σχεδιασμένη για ανάπτυξη με image και REPL, οπότε προσφέρεται πολύ για ενδοσκόπηση.
Emacs Lisp
- Αναπτύχθηκε το 1985 με σκοπό να υπάρχει μια αποδοτική γλώσσα για την επέκταση ενός επεξεργαστή κειμένου
- Δυναμικά τυποποιημένη
- Περίπου το 80% του Emacs είναι γραμμένο σε Emacs Lisp (το 20% σε C για λόγους απόδοσης)
- Λίγο διαφορετική από τις άλλες Lisp:
- Δεν είναι τυποποιημένη, εξελίσσεται ακόμα αργά
- Χωρίς αυτόματη εξάλειψη ουριαίων κλήσεων, υποστήριξη μέσω της μακροεντολής named-let (μετατρέπεται σε βρόχο while)
- Δυναμική εμβέλεια εξ ορισμού, συνιστάται λεξική εμβέλεια για νέο κώδικα
- Καλή τεκμηρίωση μέσα στον επεξεργαστή
- Πολλαπλών πλατφορμών (τρέχει όπου τρέχει και το Emacs)
- Μαθαίνεις τη γλώσσα διαβάζοντας τον κώδικα για λειτουργίες που χρησιμοποιείς καθημερινά (Emacs Core + Packages)
- Υποσύνολο της Common Lisp διαθέσιμο μέσω του πακέτου cl-lib. Ενώ η Emacs Lisp είναι αρκετά μινιμαλιστική, η Common Lisp είναι πολύ πιο πλήρης. Το πακέτο cl-lib κάνει διαθέσιμο ένα υποσύνολο της CL
Racket
- Ο Matthias Felleisen ίδρυσε την PLT Inc., η οποία τον Ιανουάριο του 1995 αποφάσισε να αναπτύξει ένα παιδαγωγικό περιβάλλον προγραμματισμού βασισμένο στη Scheme. Αρχικά ονομαζόταν PLT Scheme και αργότερα μετονομάστηκε σε Racket.
- Εκτός από παιδαγωγικό περιβάλλον προγραμματισμού, σχεδιάστηκε ως πλατφόρμα για τον σχεδιασμό και την υλοποίηση γλωσσών προγραμματισμού.
- Μοντέρνα LISP, απόγονος της Scheme
- Υποστηρίζει λογικό προγραμματισμό!
- Απλή, εκφραστική σύνταξη, που είναι ταυτόχρονα ιδανική για αρχάριους και ισχυρή στα χέρια των ειδικών
- Υποστηρίζει πολλά παραδείγματα προγραμματισμού: συναρτησιακό προγραμματισμό, αντικειμενοστρεφή προγραμματισμό, σχεδιασμό με συμβόλαιο, λογικό προγραμματισμό, μεταπρογραμματισμό
- Μια ολοκληρωμένη βασική βιβλιοθήκη
- Έρχεται με το DrRacket, ένα πλήρες IDE σχεδιασμένο για μάθηση και εξερεύνηση με ελάχιστη ταλαιπωρία
- Εξαιρετική τεκμηρίωση με άφθονες πληροφορίες και παραδείγματα
Clojure
- Αναπτύχθηκε από τον Rich Hickey με στόχο μια μοντέρνα LISP που τρέχει στη JVM και έχει εξαιρετική υποστήριξη ταυτοχρονισμού
- Διάλεκτος της LISP, αλλά και κάπως διαφορετική από τις άλλες LISP, καθώς δεν υποστηρίζει έμμεση αναδρομή ουράς (μην ανησυχείς αν δεν ξέρεις τι είναι αυτό) και έχει περισσότερες δομές δεδομένων από τις απλές λίστες: maps/sets/vectors. Όλες αυτές οι δομές δεδομένων έχουν τη δική τους σύνταξη για literals.
- Είναι επίσης όλες αμετάβλητες (immutable), αλλά έχουν ακόμα εξαιρετική απόδοση, με αναζήτηση O(log32 n) που είναι "ουσιαστικά" σταθερός χρόνος
- Πολυμορφισμός κατά την εκτέλεση μέσω multimethods και protocols
- Εξαιρετική διαλειτουργικότητα με τη JVM
- Το σύστημα προδιαγραφών δεδομένων Clojure Spec (κατά την εκτέλεση, όχι κατά τη μεταγλώττιση), σου επιτρέπει να ορίζεις τη δομή των δεδομένων, να παράγεις δεδομένα, να κάνεις property-based testing και άλλα
Περιπτώσεις χρήσης
Scheme
- Χρησιμοποιείται στην εκπαίδευση για τη διδασκαλία της επιστήμης των υπολογιστών (το επιδραστικό Structure and Interpretation of Computer Programs χρησιμοποιεί Scheme).
- Χρησιμοποιείται στην τεχνητή νοημοσύνη. Χρησιμοποιείται ως γλώσσα σεναρίων, π.χ. στο GIMP (επεξεργαστής γραφικών), σε εργαλεία CAD (Computer Aided Design) και ακόμα και σε ταινίες, με τα σενάρια διαχείρισης της μηχανής rendering του Final Fantasy: The Spirit Within
Common Lisp
- Η Common Lisp χρησιμοποιείται σε πολλά μέρη, π.χ. στην τεχνητή νοημοσύνη και στην έρευνα, αλλά και σε εμπορικές εφαρμογές: η NASA έγραψε σε Common Lisp το λογισμικό αυτόματου πιλότου του διαστημόπλοιου Deep Space One, το Viaweb γράφτηκε σε Common Lisp και αργότερα εξαγοράστηκε από τη Yahoo και μετονομάστηκε σε Yahoo Store!, και η πρώτη έκδοση του Reddit ήταν επίσης γραμμένη σε Common Lisp
Emacs Lisp
- Η Emacs Lisp χρησιμοποιείται στον... Emacs, φυσικά!
- Στον πυρήνα του, το Emacs είναι ένας διερμηνευτής για τη Emacs Lisp, μια διάλεκτο της γλώσσας προγραμματισμού Lisp, αλλά με πρόσθετες επεκτάσεις για την υποστήριξη της επεξεργασίας κειμένου
Racket
- Χρησιμοποιείται στην εκπαίδευση, καθώς η Racket σχεδιάστηκε δίνοντας έμφαση στην υποστήριξη της δημιουργίας, της απλοποίησης και της ανάλυσης γλωσσών.
- Χρησιμοποιείται στην έρευνα, καθώς η επεκτάσιμη σύνταξη και σημασιολογία της την κάνουν κατάλληλη για τον σχεδιασμό και το prototyping νέων γλωσσών και χαρακτηριστικών γλωσσών.
- Χρησιμοποιείται σε παιχνίδια, π.χ. από τον John Carmack (γνωστό από το Doom) σε ένα διαδραστικό περιβάλλον σεναρίων για VR, και η εταιρεία Naughty Dog τη χρησιμοποίησε για scripting (π.χ. στο Uncharted). Το Hacker News είναι γραμμένο σε Arc, επίσης μια Lisp, που με τη σειρά της είναι γραμμένη σε Racket.
Clojure
- Η Clojure χρησιμοποιείται για πολλά διαφορετικά πράγματα, όπως η εξαγορά της Atomist το 2022 από τη Docker, μιας πλατφόρμας ασφάλειας και αυτοματισμού containers υλοποιημένης σε Clojure.
- Ο μεγαλύτερος χρήστης Clojure στον κόσμο είναι η Nubank, μια νέα τράπεζα, που την απέκτησε πριν από λίγα χρόνια και τώρα απασχολεί την κεντρική ομάδα της Clojure.
- Χρησιμοποιείται πολύ για γρήγορο prototyping, καθώς είναι δυναμική και εξαιρετικά διαδραστική.
Από τη σκοπιά του προγραμματισμού
Όλες οι γλώσσες υποστηρίζουν τα παραδείγματα: συναρτησιακό, προστακτικό και συμβολικό. Κάποιες από αυτές υποστηρίζουν επίσης αντικειμενοστρεφή προγραμματισμό, με πιο χαρακτηριστική τη Common Lisp.
Οι Lisp είναι ως επί το πλείστον δυναμικές γλώσσες, αν και η Racket υποστηρίζει στατική τυποποίηση.
Αυτό δεν σημαίνει ότι όλες είναι διερμηνευόμενες, καθώς υπάρχει ένα μείγμα επιλογών: διερμηνευόμενες (χωρίς κανένα βήμα μεταγλώττισης), μεταγλωττισμένες σε bytecode και μετά διερμηνευόμενες, και απευθείας μεταγλωττισμένες σε κώδικα μηχανής.
Scheme
- Μινιμαλιστική, με σαφή και απλή σημασιολογία και λίγους διαφορετικούς τρόπους σχηματισμού εκφράσεων.
- Κάνει εύκολη την εκμάθηση της γλώσσας και την κατανόηση του κώδικα.
- Γι' αυτόν τον λόγο, η Scheme χρησιμοποιείται επίσης συχνά σε πολλά εισαγωγικά μαθήματα επιστήμης των υπολογιστών
- Συνεχίσεις πρώτης τάξης.
- Μια συνέχεια είναι μια αναπαράσταση της κατάστασης ενός προγράμματος.
- Οι συνεχίσεις μπορούν να χρησιμοποιηθούν για τη μοντελοποίηση της ροής ελέγχου (π.χ. μια δομή
return) ή των coroutines (που επιτρέπουν multitasking)
Common Lisp
- Επεκτάσιμο Αντικειμενοστρεφές Σύστημα με προγραμματιζόμενους συνδυασμούς μεθόδων (τόσο στον τρόπο με τον οποίο συνδυάζονται μέθοδοι υποκλάσεων και υπερκλάσεων, όσο και σε μεθόδους before, after και around, που επιτρέπουν την επέκταση συστημάτων χωρίς τροποποίησή τους)
- Προγραμματιζόμενο σύστημα συνθηκών (ένα υπερσύνολο των "εξαιρέσεων") που επιτρέπει την αποσύνδεση της αναγνώρισης των συνθηκών από την επιλογή του τρόπου αντιμετώπισής τους. Το σύστημα συνθηκών είναι πιο ευέλικτο από τα συστήματα εξαιρέσεων, γιατί αντί να παρέχει μια διμερή διαίρεση ανάμεσα στον κώδικα που σηματοδοτεί ένα σφάλμα1 και στον κώδικα που το χειρίζεται,2 το σύστημα συνθηκών χωρίζει τις ευθύνες σε τρία μέρη: σηματοδότηση μιας συνθήκης, χειρισμός της και επανεκκίνηση.
- Οι μακροεντολές επιτρέπουν την επέκταση της σύνταξης της γλώσσας, όχι απλώς τη δημιουργία επαναλαμβανόμενου κώδικα. Αυτό βοηθά να φτιάξεις μια γλώσσα που ταιριάζει στο πεδίο εφαρμογής, και όχι το αντίστροφο.
Emacs Lisp
- Εξαιρετική υποστήριξη και ενσωμάτωση με τον επεξεργαστή
- Μπορεί να χρησιμοποιηθεί για να προσαρμόσεις το Emacs ενώ αυτό τρέχει ("σαν να κάνεις εγχείρηση εγκεφάλου στον εαυτό σου" :))
- Μπορεί να χρησιμοποιηθεί σε batch mode, όπου όλες οι δυνατότητες του επεξεργαστή για την επεξεργασία κειμένου είναι διαθέσιμες (όπως buffers και εντολές μετακίνησης)
Racket
- Ισχυρό σύστημα μακροεντολών. Πάνω σε αυτό χτίζονται συντακτικές ευκολίες όπως οι μακροεντολές threading. Οι μακροεντολές είναι επίσης υγιείς, κάτι που απαντά σε ένα απλό ερώτημα: μια μακροεντολή παράγει κώδικα που τοποθετείται κάπου αλλού. Όταν αυτός ο κώδικας αξιολογηθεί, πώς πρέπει να προσδιορίσουμε τις δεσμεύσεις των αναγνωριστικών μέσα του; Οι υγιείς μακροεντολές μειώνουν την πιθανότητα απρόσμενων αποτελεσμάτων κατά τον ορισμό μακροεντολών.
- Προσανατολισμένη στις γλώσσες.
- Η Racket έρχεται με τα εργαλεία για να γράψεις τη δική σου γλώσσα προγραμματισμού ή DSL, χτισμένα πάνω στις μακροεντολές της Racket.
- Αρκετές ενσωματωμένες γλώσσες, όπως η typed Racket (με υποστήριξη στατικά ελεγχόμενων σχολιασμών τύπων), η datalog (μια γλώσσα σαν τη Prolog), την οποία υποστηρίζει το DrRacket IDE, και η scribble, ένα εργαλείο για τη δημιουργία εγγράφων σε μορφή HTML ή PDF
- Το REPL είναι κεντρικό κομμάτι της ροής ανάπτυξης, όχι μόνο για να δοκιμάζεις πράγματα ή να ψάχνεις τεκμηρίωση
Clojure
- Ισχυρό σύστημα μακροεντολών.
- Πάνω σε αυτό χτίζονται συντακτικές ευκολίες όπως οι μακροεντολές threading
- Το REPL είναι κεντρικό κομμάτι της ροής ανάπτυξης, όχι μόνο για να δοκιμάζεις πράγματα ή να ψάχνεις τεκμηρίωση
Ποια να δοκιμάσεις
- Αν δεν έχεις δοκιμάσει ποτέ Lisp, η Scheme και η Racket είναι εξαιρετικές επιλογές, αφού και οι δύο έχουν πολύ μινιμαλιστική σύνταξη.
- Παρ' όλα αυτά, η Common Lisp και η Clojure έχουν και οι δύο Learning Mode, οπότε μάλλον είναι οι καλύτερες για να μάθεις στο Exercism.
- Αν χρησιμοποιείς ήδη Emacs, η Emacs Lisp είναι φυσική επιλογή.
- Παρομοίως, αν χρησιμοποιείς κάποια γλώσσα της JVM, η Clojure είναι φυσική επιλογή.
- Η Emacs Lisp (μέσω Emacs), η Clojure (μέσω IntelliJ) και η Racket (μέσω DrRacket) έχουν όλες εξαιρετική υποστήριξη IDE.
- Υπάρχουν φυσικά και καλά IDE για τη Common Lisp και τη Scheme.
- Αν θέλεις μια πραγματικά πλήρη Lisp, η Common Lisp, η Clojure και η Racket είναι πραγματικά εκτενείς
- Αν θέλεις μια κάπως διαφορετική Lisp, η Clojure έχει αρκετά μοναδική σύνταξη για Lisp.
- Αν σε ενδιαφέρουν οι μακροεντολές και ο μεταπρογραμματισμός, βασικά όλες είναι καλές επιλογές! Αλλά αν θέλεις να φτιάχνεις νέες γλώσσες, η Racket ξεχωρίζει.
Φυσικά, αν έχεις τον χρόνο, θα σου πρότεινα να δοκιμάσεις δύο-τρεις! Επίσης, μην φοβάσαι τις παρενθέσεις! Ξέρω ότι κι εγώ τις φοβόμουν, γι' αυτό ανέβαλα την εκμάθηση της Lisp για αρκετό καιρό. Θα συνηθίσεις γρήγορα πάντως, και ίσως μάλιστα αρχίσεις να τις εκτιμάς, όπως έκανα κι εγώ. Στην πραγματικότητα, τώρα λατρεύω τις γλώσσες Lisp, με τη μινιμαλιστική σύνταξη και την εύκολη σημασιολογία τους, που παραμένουν ωστόσο εξαιρετικά εκφραστικές.