(throw (BrowserTooLameException. "Chrome oder Firefox vonnöten"))

^ SourceTalk Tage 2012 - Clojure Workshop

Clojure Workshop

        (ns de.sourcetalk.2012.clojure)
        (def smartclaim
           "Lisp's power is multiplied by the fact
            that your competitors don't get it.
                  -- Paul Graham, Beating the Averages")
      

Source Talk Tage 2012

Stefan Kamphausen

Diese Präsentation verwendet:

Clojures wichtigste Eigenschaften

JVM

Lisp

"LISP is worth learning for a different reason - the profound enlightenment experience you will have when you finally get it. That experience will make you a better programmer for the rest of your days, [..]" -- Eric S. Raymond

Funktional

Concurrency

Installation

Bevor wir anfangen können...

Emacs

Eclipse

Leiningen

        (defproject STT2012 "0.1.0-SNAPSHOT"
          :description "FIXME: write description"
          :url "http://example.com/FIXME"
          :license {:name "FIXME Eclipse Public License"
                    :url "FIXME"}
          :dependencies [[org.clojure/clojure "1.4.0"]])
      

Eine kleine Einführung

REPL

        user=> 1
        1
        user=> 123
        123
        user=> 123.456
        123.456
        user=> :keyword
        :keyword
      

Hello World

        (println "Hello World.")
        '(println "Hello World.")
      
        "Hello World."
      
        (type "Hello World.") ;; ...
      

Datentypen und -strukturen

        ["ein" "vector" :von "dingen" 12 12.34 4/3]
        {:kstring "value" :kkeyword :anothervalue
         :kint 99 :kchar \s}
        #{"ein" "Set" :von "Dingen" 123}
        '(true false nil "eine Liste")
      

Funktionen

      (defn einfache-funktion [arg1 arg2]
        (println "Arg1:" arg1 "Arg2:" arg2))
      (def quadrat (fn [x] (* x x )))
      (defn fn-mit-destruct [[a1 a2]] [a2 a1])
      (defn multi-arity-fn
        ([a1] (multi-arity-fn a1 "Default"))
        ([a1 a2] (vector a1 a2)))
      (defn fn-mit-doc
        "Dokumentation  [...]"
        [] (println "Hello World."))
    

Java Interop

        (let [pi (Math/PI)]
          (Math/cos pi))
        (new java.io.File "/etc")
        (java.io.File. "/etc")
        (.isFile (java.io.File. "/etc"))
        (.nextFloat (java.util.Random.))
        (java.net.URLEncoder/encode "Dick & Doof" "UTF-8")
        (let [pi (Math/PI)]
          (Math/cos pi))
      

Kontrollstrukturen

        (if (= 0 (+ 2 3))
          "Math is broken"
          "Puh, alles gut")
        (cond
          (= 0 (+ 2 3)) "Math is broken"
          (= 5 (+ 2 3)) "Richtig"
          (> 5 (+ 2 3)) "Auch richtig, aber...")
        (condp = (class x)
          String (.toLowerCase x)
          Integer (str (Character/toLowerCase (char x))))

      

Sequences

Abstraktion: Erstes Element und Rest: first und rest bzw. next

Einführung

        (let [s [1 2 3]]
          [(first s) (second s) (nth s 2)])
        [(first [1]) (next [1]) (rest [1])]
        (let [v ["1" :zwei]]
          [(cons 3 v) (conj v 3)])
        (range 2 10)
        (doseq [x [1 2 3] y [1 2 3]]
          (println "x und y sind jetzt" x y))
      

Was ist seqable?

        (defn seq-test [sq]
          [(first sq) (rest sq) (cons 99 sq)])
        (doseq [sq [[1 2] "abc" {:a 1, :b 2}
                    (java.util.ArrayList. [1 2])
                    (int-array 2 [4 5])]]
           (println (seq-test sq)))
      

Schweizer Messer I: map

        (map inc [1 2 3])
        (map * (range 1 4) (range 10 100))
        (map #(str "(" % ")") (range 10))
        (map #(str "(" %1 "," %2 ")") (range 10) (range 5))
        (map (fn [[x y]] (* x y)) 
             (map vector (range 1 5) (range 5 10)))
      

Laziness

        (take 5 (iterate inc 0))
        (nth (map #(* % %) (iterate inc 0)) 100)
        (def abc (map (fn [x] (printf "<%d> " x) (* 2 x))
                       (range 100)))
        (take 2 abc)
      

Schweizer Messer II: reduce

      (reduce + (range 101))
      (reduce str (range 10))
      (def x ["ich" "und" "du" "muellers" "esel" 
               "meiers" "kuh"])
      (reduce (fn [acc v] (str acc " " v)) x)
      (reductions #(str %1 " " %2) x)
      (reductions str "startwert" "SEQ")
    

Mehr Funktionen

      (filter #{2 3} (range -5 5))
      (sort < [1 4 2 66 43 3 6 7 43 88])
      (take-while #(< (count %) 2) ["a" "b" "abc"])
      (let [v [1 2 3 4]]
        [(partition 2 v) (partition 2 (next v)) 
         (partition 2 1 v)])
      (get (into {} (System/getProperties)) "os.name")
    

Workshop: Audiodaten I

Beschreibung

Heuristik: finde die erste Stelle, an der sich 10 Sample hintereinander nur um 10 unterscheiden.

Neues Projekt anlegen; Rohdaten liegen bereits vor

        sox -q orig.flac -t raw -c 1 -b 16 -e signed-integer -r 44100 - remix 1 \
        > audio.raw
      

Workshop: Audiodaten II

Tips

Workshop I: Daten einlesen

      (ns workshop.audio
       (:use [clojure.java.io :only [input-stream]])
       (:import [java.io File]))

      (defn get-raw-samples [file]
        (let [buf (byte-array (.length (File. file)))]
          ;; was ist hier ungewoehnlich?
          (with-open [is (input-stream file)]
            (.read is buf))
          (map (fn [[a b]]
                 (bit-or (bit-and a 0xff) 
                         (bit-shift-left b 8)))
               (partition 2 buf))))
    

Workshop I: Sample zu Sekunden

(defn sample-to-second 
  ([sample] (sample-to-second sample 44100))
  ([sample rate] (float (* sample (/ 1 rate)))))
    

Workshop I: Analyse

(defn analyze-file 
  ([file] (analyze-file file 10 10))
  ([file width maxdiff]
     (if-let [[values sample]
              (first 
               (drop-while 
                #(> (- (apply max (first %))
                        (apply min (first %)))
                    maxdiff)
             (map vector 
                  (partition
                   width 1 (get-raw-samples file))
                  (iterate inc 0))))]
       (format "%s: %fsec (%d@%d)" file
               (sample-to-second sample) 
               (first values) sample)
    (str file ":OK"))))
    

Concurrency

Konzepte

Wert

	"Ich bin ein String-Literal: ein Wert"
	[:das :ist :ein :Vector :von :Keywords]
	2001 ; Eine Zahl. Ein Jahr? Ein Filmtitel?
      

Identität

Zustand

	(def gruendungsjahr-fsfe 2001)
	(def einfuehrungsjahr-11-punkte-saetze 2001)
	(def identitaet "def verknuepft Wert und Identität")
      

Referenztypen

Übersicht der Referenztypen

Typ Kontext Koordination Ausführung
Var lokal eine Identität synchron
Atom übergreifend eine Identität synchron
Ref übergreifend mehrere Identitäten synchron
Agent übergreifend eine Identität asynchron

Persistente Datenstrukturen

Bit-partitionierte Bäume I

Bit-partitionierte Bäume II

Atoms

      (def atm (atom "Eins"))
      (deref atm)
      (swap! atm (constantly 1))
      @atm
    

Threads

      (.start (Thread. #(+ 2 3)))
      (defn th-info []
        (let [t (Thread/currentThread)]
          {:Name (.getName t) :ID (.getId t)}))
      (def fu (future (th-info)))
      @fu
      (doto (Thread. #(println th-info))
        (.setName "Ich, Thread")
        (.start)) ;; output in REPL/terminal
    

Refs

	(def eine-ref (ref 1))
	(dosync (alter eine-ref inc))
	(deref eine-ref)
	(dosync (alter eine-ref + 5))
      

Praxis: Refs

Erstelle zwei Refs, zähle eine hoch, die andere runter und zähle Kollisionen. Jede Addition oder Subtraktion soll in einem eigenen Thread erfolgen.

Tips

Mögliche Lösung

      (def kollisionen (atom 0))
      (def hochzaehler (ref 0))
      (def runterzaehler (ref 100))
      (defn inc-mit-zaehl [value]
        (swap! kollisionen inc)
        (inc value))
      (defn dec-mit-zaehl [value]
        (swap! kollisionen inc)
        (dec value))
      (defn stm-funktion []
        (dosync
          (alter hochzaehler   inc-mit-zaehl)
          (alter runterzaehler dec-mit-zaehl)))
      (dotimes [_ 100]
        (.start (new Thread stm-funktion)))
      [@hochzaehler @runterzaehler @kollisionen]
    
Schöner mit lokalen Variablenbindungen

Mögliche Lösung II

(defn ref-praxis [n]
  (let [koll (atom 0) 
        hochz (ref 0)
        runterz (ref n)
        inc-z (fn [val]
                (swap! koll inc)
                (inc val))
        dec-z (fn [val]
                (swap! koll inc)
                (dec val))
        stm-fn (fn []
                 (dosync
                  (alter hochz   inc-z)
                  (alter runterz dec-z)))]
    (dotimes [_ n]
      (.start (new Thread stm-fn)))
    (Thread/sleep 1000)
    [@hochz @runterz @koll]))
    

STM

Konzeptioneller Ablauf einer Transaktion

Agents

      (def ag (agent "0"))
      (dotimes [i 5]
        (.start (Thread. #(send ag str " " i))))
    

Swing

(import [java.awt.event ActionListener]
        [javax.swing JFrame JButton])
(doto (JFrame.)
  (.add (doto (JButton. "Picard")
          (.addActionListener
           (proxy [ActionListener] []
             (actionPerformed [e]
               (println "Energie!"))))))
  (.pack)
  (.setVisible true))
      

Workshop: Börsensimulation

Datenstrukturen

Validierung

UI

+---------------------+---------------------+---------+
|        Markt        |     Alle Händler    | Zustand |
+----------+----------+-----------+---------+---------+
|  Symbol  |  Anzahl  |  Händler  | Anz ges |  Fehler |
+----------+----------+-----------+---------+---------+
|   ...    |   ...    |    ...    |   ...   |   ...   |
+----------+----------+-----------+---------+---------+
      
Siehe https://github.com/daveray/seesaw

Inspiration

Zum Weiterlesen und Schauen

Vielen Dank für die Aufmerksamkeit

Hoffentlich hat es Spaß gemacht