Clojure

Från Wikipedia
Hoppa till: navigering, sök
Clojure[1]
Paradigm funktionell
Gavs ut 2009
Skapat av Rich Hickey
Utvecklare Rich Hickey, m.fl.[2]
Senaste version 1.5.1 (10 Mars, 2013)
Datatypsdisciplin starkt, dynamiskt
Influerat av Lisp, Haskell, Java, Python [3]
Platform JVM, CLR
Licens Eclipse Public License
Webbplats clojure.org

Clojure är en modern dialekt av inom Lisp-familjen av programmeringsspråk. Clojure skapades av Rich Hickey och släpptes i en första version i slutet av 2009. Det är ett general-purpose språk som stödjer interaktiv utveckling som uppmuntrar en funktionell programmeringsstil. Clojure (liksom andra programmeringsspråk) körs på Java Virtual Machine, Common Language Runtime och kan kompileras till JavaScript.

Motiv[redigera | redigera wikitext]

Enligt skaparen, Rich Hickey, är språket tänkt att vara pragmatiskt och ha god prestanda, snarare än att vara ett akademiskt projekt[4]. Vidare ger Clojures API ett jämförelsevis enkelt förfarande för att inter-operera med existerande Java-bibliotek.

Kännetecken[redigera | redigera wikitext]

Clojure har ett antal intressanta funktioner och kännetecken som underlätta utveckling, debugging och underhåll av mjukvara. Exempel på dessa är:

  • STM (Software Transactional Memory) med inbyggda makron för att genomföra synkrona transaktioner på gemensamma data
  • Oföränderliga datastrukturer
  • Funktioner är av första klassen
  • Polymorfism under körning

Syntax[redigera | redigera wikitext]

Clojures syntax byggs på S-uttryck. Väldigt många andra Lisps använder också dessa S-uttryck. Dessa läses in av REPL:n till datastrukturer innan kompilering, då manipuleringen via makron genomförs. Clojure är en Lisp-1, vilket innebär att funktioner och värden delar på ett namespace[5]. Språket är inte kodkompatibelt med andra Lisp-dialekter.

Det som i huvudsak gör Clojure kod-inkompatibelt med andra dialekter är bl.a. det faktum att Clojure använder mer specifika teckenpar för att ange olika sorters datastrukturer[6].

I Clojure används [] för att ange vektorer, {} för att ange associativa vektorer och #{} för att ange associativa vektorer med unika värden.

Exempel[redigera | redigera wikitext]

Hello world:

(println "Hello, world!")

Nedan definieras en funktion som tar en parameter (x) som anges som en vektor med ett element. Funktionen applicerar multiplikationsfunktionen * på parametern två gånger. I Clojure, som med andra Lisp-dialekter, returneras det värde som den sist evaluerade funktionen returnerar automatiskt:

(defn square [x]
  (* x x))

Genom att använda Javas Swing bibliotek är det möjligt att rita grafiska gränssnitt (ytterligare ett Hello World-exempel):

(javax.swing.JOptionPane/showMessageDialog nil "Hello World" )

Nedan ges exempel på en trådsäker generator av unika serienummer (notera att liksom många andra Lisp dialekter, har Clojure en inbyggd gensym funktion för detta syfte):

(let [i (atom 0)]
  (defn generate-unique-id
    "Returns a distinct numeric ID for each call."
    []
    (swap! i inc)))

En anonym underklass av java.io.Writer som inte skriver till någonting, och ett makro som använder detta för att tysta alla 'prints' inuti det:

(def bit-bucket-writer
  (proxy [java.io.Writer] []
    (write [buf] nil)
    (close []    nil)
    (flush []    nil)))
 
(defmacro noprint
  "Evaluates the given expressions with all printing to *out* silenced."
  [& forms]
  `(binding [*out* bit-bucket-writer]
     ~@forms))
 
(noprint
  (println "Hello, nobody!"))

Tio trådar manipulerar en gemensam datastruktur, vilken består av 100 vektorer, där varje vektor använder 10 (initiellt sekventiella) unika tal. Varje tråd väljer repetitivt två slumpvisa positioner i två slumpvisa vektorer och byter plats på dem. Alla ändringar till vektorerna händer i transaktioner genom att använda clojures software transactional memory system. Tack vare denna transaktionskontroll tappas inget data bort trots att man manipulerar vektorerna från flera trådar parallellt 100 000 gånger i exempelet.

(defn run [nvecs nitems nthreads niters]
  (let [vec-refs (vec (map (comp ref vec)
                           (partition nitems (range (* nvecs nitems)))))
        swap #(let [v1 (rand-int nvecs)
                    v2 (rand-int nvecs)
                    i1 (rand-int nitems)
                    i2 (rand-int nitems)]
                (dosync
                 (let [temp (nth @(vec-refs v1) i1)]
                   (alter (vec-refs v1) assoc i1 (nth @(vec-refs v2) i2))
                   (alter (vec-refs v2) assoc i2 temp))))
        report #(do
                 (prn (map deref vec-refs))
                 (println "Distinct:"
                          (count (distinct (apply concat (map deref vec-refs))))))]
    (report)
    (dorun (apply pcalls (repeat nthreads #(dotimes [_ niters] (swap)))))
    (report)))
 
(run 100 10 10 100000)

Utfall av föregående exempel:

([0 1 2 3 4 5 6 7 8 9] [10 11 12 13 14 15 16 17 18 19] ...
 [990 991 992 993 994 995 996 997 998 999])
Distinct: 1000
 
([382 318 466 963 619 22 21 273 45 596] [808 639 804 471 394 904 952 75 289 778] ...
 [484 216 622 139 651 592 379 228 242 355])
Distinct: 1000


Den här artikeln är helt eller delvis baserad på material från engelskspråkiga Wikipedia
  1. ^ ”WikiPedia:Clojure (programming language)”. http://en.wikipedia.org/wiki/Clojure. Läst 15 november 2012. 
  2. ^ ”Bidragsgivare av kod till projektet”. http://clojure.org/contributing. Läst 15 november 2012. 
  3. ^ ”Influenser”. http://cdn.oreilly.com/oreilly/booksamplers/9781449394707_sampler.pdf. Läst 22 September 2013. 
  4. ^ ”Clojure Rationale”. http://clojure.org/rationale. Läst 15 november 2012. 
  5. ^ ”Technical Issues of Separation in Function Cells and Value Cells”. http://www.nhplace.com/kent/Papers/Technical-Issues.html. Läst 15 november 2012. 
  6. ^ ”Presentation med Rich Hickey”. http://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey. Läst 15 november 2012.