ΗClojure (προφέρεται όπως ο αγγλικός όρος "closure"[1]) είναι μια σύγχρονη διάλεκτος τηςγλώσσας προγραμματισμούLisp. Είναι γλώσσα γενικού σκοπού, υποστηρίζει τη διαδραστική ανάπτυξη, ενθαρρύνει τοστυλ συναρτησιακού προγραμματισμού και απλοποιεί τονπολυνηματικό προγραμματισμό. Η Clojure τρέχει στηνΕικονική μηχανή της Java (JVM) και στηνCommon Language Runtime (CLR). Η Clojure τηρεί τη φιλοσοφία "κώδικας-σαν-δεδομένα (code-as-data)" και έχει ένα εκτεταμένο σύστημαμακροεντολών.
Ο Rich Hickey ανέπτυξε την Clojure γιατί ήθελε μια σύγχρονη διάλεκτο τηςLisp γιασυναρτησιακό προγραμματισμό, που να συνεργάζεται με την καθιερωμένη πλατφόρμα τηςJava και να είναι σχεδιασμένη για ταυτοχρονισμό.[2][3]
Η προσέγγιση της Clojure στον ταυτοχρονισμό χαρακτηρίζεται από την έννοια των identities[4], τα οποία αναπαριστούν αμετάβλητες καταστάσεις στο χρόνο. Επειδή η κατάσταση αποτελείται από αμετάβλητες τιμές, οποιοσδήποτε αριθμός υποπρογραμμάτων-"εργατών" ("workers") μπορεί να τις χρησιμοποιεί παράλληλα, και ο ταυτοχρονισμός εξαρτάται από το πώς ελέγχονται οι αλλαγές από τη μια κατάσταση στην άλλη. Για αυτόν το λόγο, η Clojure παρέχει αρκετούς τύπους μεταβλητής αναφοράς (mutable reference types), ο καθένας από τους οποίους έχει ξεκάθαρη σημασιολογία όσον αφορά τη μετάβαση μεταξύ των καταστάσεων.
Όπως και όλες οι άλλες Lisp, ησύνταξη της Clojure βασίζεται σεσυμβολικές εκφράσεις (S-expressions) που αρχικά διαβάζονται σε ειδικές δομές δεδομένων από έναν αναγνώστη (reader) πριν τη μεταγλώττιση. Εκτός από λίστες, ο αναγνώστης της Clojure υποστηρίζει ρητή σύνταξη γιααντιστοιχίσεις, σύνολα καιδιανύσματα (vectors), και αυτά δίνονται στο μεταγλωττιστή όπως είναι. Με άλλα λόγια, ο μεταγλωττιστής της Clojure δε μεταγλωττίζει μόνο λίστες αλλά υποστηρίζει άμεσα όλους τους προαναφερθέντες τύπους.Η Clojure είναι μιαLisp-1, και δεν προορίζεται να είναι συμβατή σε επίπεδο κώδικα με άλλες διαλέκτους της Lisp.
Τοσύστημα μακροεντολών της Clojure μοιάζει με αυτό τηςCommon Lisp με την εξαίρεση ότι η έκδοση της Clojure για τον τελεστή backquote (που καλείται "syntax quote") δίνει στα σύμβολα και το χώρο ονομάτων τους (namespace). Επειδή απαγορεύεται η δέσμευση ονομάτων που περιέχουν χώρο ονομάτων, αποφεύγονται καταστάσεις ακούσιας δέσμευσης ονομάτων. Μια επέκταση μακροεντολής μπορεί να δεσμεύει ονόματα, αλλά αυτό πρέπει να γίνει ρητά από τον προγραμματιστή.
Η Clojure επίσης απαγορεύει την επαναδέσμευση καθολικών ονομάτων σε άλλους χώρους ονομάτων που έχουν εισαχθεί (import) στον τρέχοντα χώρο ονομάτων.
"Γεια σου, κόσμε!":
(println"Γεια σου, κόσμε!")
"Γεια σου, κόσμε!" (GUI):
(javax.swing.JOptionPane/showMessageDialognil"Γεια σου, κόσμε!")
Μια γεννήτρια μοναδικών σειριακών αριθμών ασφαλής για πολυνηματική εκτέλεση (thread-safe):
(let[i(atom0)](defngenerate-unique-id"Επιστρέφει ένα μοναδικό αριθμητικό ID για κάθε κλήση."[](swap!iinc)))
Μια ανώνυμη υποκλάση τηςjava.io.Writer που δεν γράφει πουθενά, και μια μακροεντολή που τη χρησιμοποιεί για να κρύψει όλες τις εντολές εξόδου (print) σε αυτή:
(defbit-bucket-writer(proxy[java.io.Writer][](write[buf]nil)(close[]nil)(flush[]nil)))(defmacronoprint"Αποτιμά όλες τις εκφράσεις που δίνονται, αποσιωπώντας την έξοδο *out*."[&forms]`(binding[*out*bit-bucket-writer]~@forms))(noprint(println"Hello, nobody!"))
10νήματα που χειρίζονται μια κοινή δομή δεδομένων, η οποία αποτελείται από 100 διανύσματα, το καθένα από τα οποία περιέχει 10 (αρχικά διαδοχικούς) αριθμούς. Κάθε νήμα τότε επαναλαμβανόμενα επιλέγει δύο τυχαίες θέσεις σε δύο τυχαία διανύσματα και τα αντιμεταθέτει:
Όλες οι αλλαγές στα διανύσματα συμβαίνουν μέσα σε συναλλαγές χρησιμοποιώντας το σύστημα μνήμης συναλλαγών σε λογισμικό της Clojure. Με αυτόν τον τρόπο, ακόμα και μετά από 100.000 επαναλήψεις κάθε νήματος δε χάνεται κανένας αριθμός.
(defnrun[nvecsnitemsnthreadsniters](let[vec-refs(vec(map(comprefvec)(partitionnitems(range(*nvecsnitems)))))swap#(let[v1(rand-intnvecs)v2(rand-intnvecs)i1(rand-intnitems)i2(rand-intnitems)](dosync(let[temp(nth@(vec-refsv1)i1)](alter(vec-refsv1)associ1(nth@(vec-refsv2)i2))(alter(vec-refsv2)associ2temp))))report#(do(prn(mapderefvec-refs))(println"Distinct:"(count(distinct(applyconcat(mapderefvec-refs))))))](report)(dorun(applypcalls(repeatnthreads#(dotimes[_niters](swap)))))(report)))(run1001010100000)
Έξοδος του προηγούμενου παραδείγματος:
([0123456789][10111213141516171819]...[990991992993994995996997998999])Distinct:1000([382318466963619222127345596][80863980447139490495275289778]...[484216622139651592379228242355])Distinct:1000
| ΤαWikimedia Commons έχουν πολυμέσα σχετικά με το θέμα Clojure |