;; book v3.0 pg 18 (defmulti blank? class) (defmethod blank? String [s] (every? #{\space} s)) (defmethod blank? nil [_] true) (blank? "") (blank? "a") (blank? " ") (blank? nil) ;; is nil the same as Java null? (defstruct person :first-name :last-name) user/person person (macroexpand '(defstruct person :first-name :last-name)) ;; (def person (clojure/create-struct :first-name :last-name)) [1, 2, 3, 4] [1 2 3 4] [1, 2, 3, 4,] ;; nice... ;; pg 18 book v2.0 (defn testme [x] (cond (< x 10) "less" (> x 10) "more" true "dunno")) (testme 0) (testme 10) (testme 11) ;; pg 19 book v2.0 (let [compositions (list {:name "Requiem" :composer "Some Tool"} {:name "Movement" :composer "Dead Guy"} ) ] (for [c compositions :when (= "Requiem" (:name c))] (:composer c))) (for [c '(1 2 3 4)] c) (for [c '(1 2 3 4) :when (= 0 (rem c 2))] c) (. #{\space} getClass) ;; #=clojure.lang.PersistentHashSet (. "\t" (charAt 0)) ;; \tab (. #{} getClass) ;; #=clojure.lang.PersistentHashSet (def accounts (ref #{})) (defstruct account :id :balance) (dosync (alter accounts conj (struct account "CLJ" 1000.00))) accounts @accounts (deref accounts) (System/getProperties) (. (System/getProperties) getClass) (.. [] getClass getProtectionDomain getCodeSource) ;; #<(file:/home/mortis/personal/projects/clojure/clojure.org/clojure/trunk/clojure.jar )> ;; book v3.0 pg 24 (.start (Thread. (fn [] (println "Hello " (Thread/currentThread))))) (defn hello [name] (str "Hello, " name)) (hello "foo") (/ 1 0) (.printStackTrace *e) (conj #{} "foo") (conj (conj #{} "stu") "foo") (def visitors (ref #{})) (dosync (commute visitors conj "stu")) visitors (deref visitors) (dosync (commute visitors conj "bob")) (deref visitors) @visitors (commute visitors conj "sal") ;; => exception (defn hello [name] (let [past-visitor (@visitors name)] (dosync (commute visitors conj name)) (if past-visitor (str "Welcome back, " name) (str "Hello, " name)))) (hello "bob") (hello "sal") (hello "bob") ;; pg 26 (require :verbse 'clojure.contrib.str-utils) (require 'introduction) (ns-map 'introduction) ; {sorted-map #=(var clojure/sorted-map), read-line #=(var clojure/read-line), re-pattern #=(var clojure/re-pattern), keyword? #=(var clojure/keyword?), val #=(var clojure/val), ProcessBuilder #=java.lang.ProcessBuilder, Enum #=java.lang.Enum, SuppressWarnings #=java.lang.SuppressWarnings, ! #=(var clojure/!), max-key #=(var clojure/max-key), list* #=(var clojure/list*), ns-aliases #=(var clojure/ns-aliases), == #=(var clojure/==), longs #=(var clojure/longs), special-form-anchor #=(var clojure/special-form-anchor), Throwable #=java.lang.Throwable, InterruptedException #=java.lang.InterruptedException, instance? #=(var clojure/instance?), syntax-symbol-anchor #=(var clojure/syntax-symbol-anchor), Thread$UncaughtExceptionHandler #=java.lang.Thread$UncaughtExceptionHandler, RuntimeException #=java.lang.RuntimeException, format #=(var clojure/format), sequential? #=(var clojure/sequential?), fn? #=(var clojure/fn?), empty #=(var clojure/empty), dorun #=(var clojure/dorun), time #=(var clojure/time), remove-method #=(var clojure/remove-method), Thread$State #=java.lang.Thread$State, gensym #=(var clojure/gensym), not= #=(var clojure/not=), *3 #=(var clojure/*3), ArrayIndexOutOfBoundsException #=java.lang.ArrayIndexOutOfBoundsException, unchecked-multiply #=(var clojure/unchecked-multiply), doseq #=(var clojure/doseq), bit-or #=(var clojure/bit-or), aset-byte #=(var clojure/aset-byte), hash-set #=(var clojure/hash-set), add-watch #=(var clojure/add-watch), unchecked-dec #=(var clojure/unchecked-dec), some #=(var clojure/some), nil? #=(var clojure/nil?), IllegalAccessError #=java.lang.IllegalAccessError, string? #=(var clojure/string?), second #=(var clojure/second), keys #=(var clojure/keys), for #=(var clojure/for), *2 #=(var clojure/*2), long-array #=(var clojure/long-array), cond #=(var clojure/cond), Process #=java.lang.Process, SecurityException #=java.lang.SecurityException, bit-set #=(var clojure/bit-set), InstantiationException #=java.lang.InstantiationException, fn #=(var clojure/fn), sorted? #=(var clojure/sorted?), ThreadGroup #=java.lang.ThreadGroup, ns-unalias #=(var clojure/ns-unalias), ns-publics #=(var clojure/ns-publics), System #=java.lang.System, EnumConstantNotPresentException #=java.lang.EnumConstantNotPresentException, OutOfMemoryError #=java.lang.OutOfMemoryError, Double #=java.lang.Double, dosync #=(var clojure/dosync), all-ns #=(var clojure/all-ns), long #=(var clojure/long), with-open #=(var clojure/with-open), add-classpath #=(var clojure/add-classpath), false? #=(var clojure/false?), await1 #=(var clojure/await1), true? #=(var clojure/true?), sync #=(var clojure/sync), short #=(var clojure/short), ns-unmap #=(var clojure/ns-unmap), repeat #=(var clojure/repeat), Package #=java.lang.Package, zipmap #=(var clojure/zipmap), distinct #=(var clojure/distinct), get-in #=(var clojure/get-in), bit-xor #=(var clojure/bit-xor), char-escape-string #=(var clojure/char-escape-string), complement #=(var clojure/complement), let #=(var clojure/let), get-validator #=(var clojure/get-validator), dotimes #=(var clojure/dotimes), *ns* #=(var clojure/*ns*), defmethod #=(var clojure/defmethod), derive #=(var clojure/derive), aset-float #=(var clojure/aset-float), scan #=(var clojure/scan), lazy-cat #=(var clojure/lazy-cat), ExceptionInInitializerError #=java.lang.ExceptionInInitializerError, commute #=(var clojure/commute), defstruct #=(var clojure/defstruct), with-in-str #=(var clojure/with-in-str), rem #=(var clojure/rem), set-validator #=(var clojure/set-validator), odd? #=(var clojure/odd?), symbol? #=(var clojure/symbol?), *print-level* #=(var clojure/*print-level*), *allow-unresolved-vars* #=(var clojure/*allow-unresolved-vars*), RuntimePermission #=java.lang.RuntimePermission, *macro-meta* #=(var clojure/*macro-meta*), UnknownError #=java.lang.UnknownError, proxy-call-with-super #=(var clojure/proxy-call-with-super), ns-interns #=(var clojure/ns-interns), re-matches #=(var clojure/re-matches), split-with #=(var clojure/split-with), find-doc #=(var clojure/find-doc), loop #=(var clojure/loop), rfirst #=(var clojure/rfirst), gen-and-load-class #=(var clojure/gen-and-load-class), IncompatibleClassChangeError #=java.lang.IncompatibleClassChangeError, ArithmeticException #=java.lang.ArithmeticException, import #=(var clojure/import), symbol #=(var clojure/symbol), vals #=(var clojure/vals), print-doc #=(var clojure/print-doc), select-keys #=(var clojure/select-keys), re-matcher #=(var clojure/re-matcher), rand #=(var clojure/rand), deref #=(var clojure/deref), StackTraceElement #=java.lang.StackTraceElement, unchecked-inc #=(var clojure/unchecked-inc), *math-context* #=(var clojure/*math-context*), read #=(var clojure/read), make-hierarchy #=(var clojure/make-hierarchy), + #=(var clojure/+), number? #=(var clojure/number?), descendants #=(var clojure/descendants), into-array #=(var clojure/into-array), last #=(var clojure/last), unchecked-negate #=(var clojure/unchecked-negate), integer? #=(var clojure/integer?), NoSuchFieldError #=java.lang.NoSuchFieldError, alter #=(var clojure/alter), prn #=(var clojure/prn), with-meta #=(var clojure/with-meta), with-out-str #=(var clojure/with-out-str), InternalError #=java.lang.InternalError, floats #=(var clojure/floats), * #=(var clojure/*), fnseq #=(var clojure/fnseq), when-not #=(var clojure/when-not), Thread #=java.lang.Thread, butlast #=(var clojure/butlast), - #=(var clojure/-), SecurityManager #=java.lang.SecurityManager, account #=(var introduction/account), reversible? #=(var clojure/reversible?), rseq #=(var clojure/rseq), send-off #=(var clojure/send-off), seq? #=(var clojure/seq?), Cloneable #=java.lang.Cloneable, refer-clojure #=(var clojure/refer-clojure), NegativeArraySizeException #=java.lang.NegativeArraySizeException, StringBuilder #=java.lang.StringBuilder, identical? #=(var clojure/identical?), .. #=(var clojure/..), print #=(var clojure/print), *command-line-args* #=(var clojure/*command-line-args*), bit-flip #=(var clojure/bit-flip), zero? #=(var clojure/zero?), bit-and #=(var clojure/bit-and), Appendable #=java.lang.Appendable, re-groups #=(var clojure/re-groups), *warn-on-reflection* #=(var clojure/*warn-on-reflection*), newline #=(var clojure/newline), cache-seq #=(var clojure/cache-seq), replicate #=(var clojure/replicate), distinct? #=(var clojure/distinct?), remove-ns #=(var clojure/remove-ns), ratio? #=(var clojure/ratio?), xml-seq #=(var clojure/xml-seq), vec #=(var clojure/vec), concat #=(var clojure/concat), update-in #=(var clojure/update-in), vector #=(var clojure/vector), Byte #=java.lang.Byte, conj #=(var clojure/conj), bases #=(var clojure/bases), / #=(var clojure//), Math #=java.lang.Math, Exception #=java.lang.Exception, unchecked-add #=(var clojure/unchecked-add), ref-set #=(var clojure/ref-set), assoc #=(var clojure/assoc), IllegalAccessException #=java.lang.IllegalAccessException, seque #=(var clojure/seque), aset-char #=(var clojure/aset-char), boolean #=(var clojure/boolean), read-string #=(var clojure/read-string), neg? #=(var clojure/neg?), float-array #=(var clojure/float-array), doubles #=(var clojure/doubles), ClassNotFoundException #=java.lang.ClassNotFoundException, UnsatisfiedLinkError #=java.lang.UnsatisfiedLinkError, isa? #=(var clojure/isa?), doto #=(var clojure/doto), IllegalArgumentException #=java.lang.IllegalArgumentException, remove-watch #=(var clojure/remove-watch), print-str #=(var clojure/print-str), *e #=(var clojure/*e), gen-and-save-class #=(var clojure/gen-and-save-class), AssertionError #=java.lang.AssertionError, rsubseq #=(var clojure/rsubseq), *flush-on-newline* #=(var clojure/*flush-on-newline*), *out* #=(var clojure/*out*), Short #=java.lang.Short, StrictMath #=java.lang.StrictMath, vector? #=(var clojure/vector?), split-at #=(var clojure/split-at), ns-refers #=(var clojure/ns-refers), create-struct #=(var clojure/create-struct), proxy-super #=(var clojure/proxy-super), int-array #=(var clojure/int-array), float #=(var clojure/float), rrest #=(var clojure/rrest), assert #=(var clojure/assert), map #=(var clojure/map), ClassCircularityError #=java.lang.ClassCircularityError, memfn #=(var clojure/memfn), double-array #=(var clojure/double-array), accessor #=(var clojure/accessor), NoSuchFieldException #=java.lang.NoSuchFieldException, *print-length* #=(var clojure/*print-length*), class? #=(var clojure/class?), rand-int #=(var clojure/rand-int), Comparable #=java.lang.Comparable, *1 #=(var clojure/*1), aset-short #=(var clojure/aset-short), prn-str #=(var clojure/prn-str), iterate #=(var clojure/iterate), when-first #=(var clojure/when-first), slurp #=(var clojure/slurp), mapcat #=(var clojure/mapcat), assoc-in #=(var clojure/assoc-in), Readable #=java.lang.Readable, special-symbol? #=(var clojure/special-symbol?), ref #=(var clojure/ref), UnsupportedClassVersionError #=java.lang.UnsupportedClassVersionError, find-var #=(var clojure/find-var), inc #=(var clojure/inc), IllegalThreadStateException #=java.lang.IllegalThreadStateException, definline #=(var clojure/definline), unchecked-subtract #=(var clojure/unchecked-subtract), ns-name #=(var clojure/ns-name), defn- #=(var clojure/defn-), *file* #=(var clojure/*file*), re-find #=(var clojure/re-find), bit-not #=(var clojure/bit-not), construct-proxy #=(var clojure/construct-proxy), destructure #=(var clojure/destructure), visitors #=(var introduction/visitors), Iterable #=java.lang.Iterable, seq #=(var clojure/seq), to-array-2d #=(var clojure/to-array-2d), sorted-map-by #=(var clojure/sorted-map-by), filter #=(var clojure/filter), Object #=java.lang.Object, var? #=(var clojure/var?), comment #=(var clojure/comment), key #=(var clojure/key), class #=(var clojure/class), re-seq #=(var clojure/re-seq), ns #=(var clojure/ns), empty? #=(var clojure/empty?), test #=(var clojure/test), create-ns #=(var clojure/create-ns), VirtualMachineError #=java.lang.VirtualMachineError, name #=(var clojure/name), list? #=(var clojure/list?), InheritableThreadLocal #=java.lang.InheritableThreadLocal, ThreadLocal #=java.lang.ThreadLocal, ClassLoader #=java.lang.ClassLoader, nthrest #=(var clojure/nthrest), aset #=(var clojure/aset), doall #=(var clojure/doall), macroexpand-1 #=(var clojure/macroexpand-1), not-any? #=(var clojure/not-any?), resultset-seq #=(var clojure/resultset-seq), into #=(var clojure/into), with-precision #=(var clojure/with-precision), *use-context-classloader* #=(var clojure/*use-context-classloader*), CloneNotSupportedException #=java.lang.CloneNotSupportedException, ffirst #=(var clojure/ffirst), bit-clear #=(var clojure/bit-clear), TypeNotPresentException #=java.lang.TypeNotPresentException, load-reader #=(var clojure/load-reader), or #=(var clojure/or), hash #=(var clojure/hash), print-ctor #=(var clojure/print-ctor), associative? #=(var clojure/associative?), Void #=java.lang.Void, Character #=java.lang.Character, float? #=(var clojure/float?), drop-last #=(var clojure/drop-last), replace #=(var clojure/replace), NoClassDefFoundError #=java.lang.NoClassDefFoundError, decimal? #=(var clojure/decimal?), defn #=(var clojure/defn), parents #=(var clojure/parents), map? #=(var clojure/map?), IllegalStateException #=java.lang.IllegalStateException, LinkageError #=java.lang.LinkageError, quot #=(var clojure/quot), file-seq #=(var clojure/file-seq), send #=(var clojure/send), with-local-vars #=(var clojure/with-local-vars), reverse #=(var clojure/reverse), count #=(var clojure/count), Boolean #=java.lang.Boolean, get-proxy-class #=(var clojure/get-proxy-class), set #=(var clojure/set), when-let #=(var clojure/when-let), comp #=(var clojure/comp), nth #=(var clojure/nth), byte #=(var clojure/byte), *err* #=(var clojure/*err*), constantly #=(var clojure/constantly), load #=(var clojure/load), namespace #=(var clojure/namespace), pr-str #=(var clojure/pr-str), < #=(var clojure/<), rationalize #=(var clojure/rationalize), sort-by #=(var clojure/sort-by), String #=java.lang.String, cycle #=(var clojure/cycle), peek #=(var clojure/peek), accounts #=(var introduction/accounts), reduce #=(var clojure/reduce), interleave #=(var clojure/interleave), InstantiationError #=java.lang.InstantiationError, amap #=(var clojure/amap), -> #=(var clojure/->), cons #=(var clojure/cons), macroexpand #=(var clojure/macroexpand), var-set #=(var clojure/var-set), Float #=java.lang.Float, str #=(var clojure/str), aset-boolean #=(var clojure/aset-boolean), ns-imports #=(var clojure/ns-imports), first #=(var clojure/first), bean #=(var clojure/bean), = #=(var clojure/=), Runnable #=java.lang.Runnable, var-get #=(var clojure/var-get), range #=(var clojure/range), tree-seq #=(var clojure/tree-seq), defmacro #=(var clojure/defmacro), IndexOutOfBoundsException #=java.lang.IndexOutOfBoundsException, aset-double #=(var clojure/aset-double), enumeration-seq #=(var clojure/enumeration-seq), prefer-method #=(var clojure/prefer-method), ensure #=(var clojure/ensure), find-ns #=(var clojure/find-ns), not-every? #=(var clojure/not-every?), struct-map #=(var clojure/struct-map), > #=(var clojure/>), max #=(var clojure/max), proxy-mappings #=(var clojure/proxy-mappings), identity #=(var clojure/identity), ints #=(var clojure/ints), min-key #=(var clojure/min-key), subs #=(var clojure/subs), ClassFormatError #=java.lang.ClassFormatError, agent-errors #=(var clojure/agent-errors), BigInteger #=java.math.BigInteger, clear-agent-errors #=(var clojure/clear-agent-errors), printf #=(var clojure/printf), ns-resolve #=(var clojure/ns-resolve), NullPointerException #=java.lang.NullPointerException, Callable #=java.util.concurrent.Callable, method-sig #=(var clojure/method-sig), >= #=(var clojure/>=), Compiler #=clojure.lang.Compiler, NoSuchMethodError #=java.lang.NoSuchMethodError, shutdown-agents #=(var clojure/shutdown-agents), ClassCastException #=java.lang.ClassCastException, even? #=(var clojure/even?), require #=(var clojure/require), bit-shift-left #=(var clojure/bit-shift-left), touch #=(var clojure/touch), compare #=(var clojure/compare), Class #=java.lang.Class, cast #=(var clojure/cast), supers #=(var clojure/supers), load-string #=(var clojure/load-string), get #=(var clojure/get), <= #=(var clojure/<=), StringIndexOutOfBoundsException #=java.lang.StringIndexOutOfBoundsException, await #=(var clojure/await), resolve #=(var clojure/resolve), print-method #=(var clojure/print-method), loaded-libs #=(var clojure/loaded-libs), force #=(var clojure/force), partial #=(var clojure/partial), pmap #=(var clojure/pmap), if-let #=(var clojure/if-let), comparator #=(var clojure/comparator), pos? #=(var clojure/pos?), Override #=java.lang.Override, char #=(var clojure/char), take-while #=(var clojure/take-while), blank? #=(var introduction/blank?), and #=(var clojure/and), lazy-cons #=(var clojure/lazy-cons), refer #=(var clojure/refer), underive #=(var clojure/underive), in-ns #=(var clojure/in-ns), iterator-seq #=(var clojure/iterator-seq), declare #=(var clojure/declare), ancestors #=(var clojure/ancestors), locking #=(var clojure/locking), partition #=(var clojure/partition), ThreadDeath #=java.lang.ThreadDeath, *proxy-classes* #=(var clojure/*proxy-classes*), contains? #=(var clojure/contains?), update-proxy #=(var clojure/update-proxy), CharSequence #=java.lang.CharSequence, interpose #=(var clojure/interpose), aset-int #=(var clojure/aset-int), load-file #=(var clojure/load-file), delay #=(var clojure/delay), apply #=(var clojure/apply), defmulti #=(var clojure/defmulti), proxy #=(var clojure/proxy), subvec #=(var clojure/subvec), rest #=(var clojure/rest), keyword #=(var clojure/keyword), Number #=java.lang.Number, ns-map #=(var clojure/ns-map), fibs #=(var introduction/fibs), int #=(var clojure/int), bigdec #=(var clojure/bigdec), *agent* #=(var clojure/*agent*), IllegalMonitorStateException #=java.lang.IllegalMonitorStateException, aset-long #=(var clojure/aset-long), Error #=java.lang.Error, NumberFormatException #=java.lang.NumberFormatException, struct #=(var clojure/struct), VerifyError #=java.lang.VerifyError, array-map #=(var clojure/array-map), bigint #=(var clojure/bigint), dec #=(var clojure/dec), println #=(var clojure/println), aget #=(var clojure/aget), pr #=(var clojure/pr), drop #=(var clojure/drop), gen-class #=(var clojure/gen-class), eval #=(var clojure/eval), aclone #=(var clojure/aclone), char-name-string #=(var clojure/char-name-string), pop #=(var clojure/pop), primitives-classnames #=(var clojure/primitives-classnames), StringBuffer #=java.lang.StringBuffer, defonce #=(var clojure/defonce), bit-shift-right #=(var clojure/bit-shift-right), NoSuchMethodException #=java.lang.NoSuchMethodException, delay? #=(var clojure/delay?), num #=(var clojure/num), disj #=(var clojure/disj), *print-readably* #=(var clojure/*print-readably*), Long #=java.lang.Long, rational? #=(var clojure/rational?), merge-with #=(var clojure/merge-with), take-nth #=(var clojure/take-nth), BigDecimal #=java.math.BigDecimal, *print-meta* #=(var clojure/*print-meta*), double #=(var clojure/double), *in* #=(var clojure/*in*), line-seq #=(var clojure/line-seq), take #=(var clojure/take), when #=(var clojure/when), areduce #=(var clojure/areduce), set? #=(var clojure/set?), make-array #=(var clojure/make-array), alias #=(var clojure/alias), ArrayStoreException #=java.lang.ArrayStoreException, use #=(var clojure/use), alength #=(var clojure/alength), to-array #=(var clojure/to-array), hash-map #=(var clojure/hash-map), bit-and-not #=(var clojure/bit-and-not), UnsupportedOperationException #=java.lang.UnsupportedOperationException, repeatedly #=(var clojure/repeatedly), frest #=(var clojure/frest), remove #=(var clojure/remove), find #=(var clojure/find), coll? #=(var clojure/coll?), drop-while #=(var clojure/drop-while), not-empty #=(var clojure/not-empty), print-special-doc #=(var clojure/print-special-doc), println-str #=(var clojure/println-str), list #=(var clojure/list), every? #=(var clojure/every?), flush #=(var clojure/flush), Integer #=java.lang.Integer, sort #=(var clojure/sort), Deprecated #=java.lang.Deprecated, StackOverflowError #=java.lang.StackOverflowError, dissoc #=(var clojure/dissoc), not #=(var clojure/not), binding #=(var clojure/binding), doc #=(var clojure/doc), agent #=(var clojure/agent), hello #=(var introduction/hello), sorted-set #=(var clojure/sorted-set), alter-var-root #=(var clojure/alter-var-root), merge #=(var clojure/merge), subseq #=(var clojure/subseq), min #=(var clojure/min), print-simple #=(var clojure/print-simple), bit-test #=(var clojure/bit-test), AbstractMethodError #=java.lang.AbstractMethodError, await-for #=(var clojure/await-for), Runtime #=java.lang.Runtime, meta #=(var clojure/meta), unchecked-divide #=(var clojure/unchecked-divide)} (. (ns-map 'introduction) getClass) ;; #=clojure.lang.PersistentHashMap (println "3") (take 10 introduction/fibs) ;; use imports, while require doesn't (use 'introduction) (take 10 fibs) ;; during development, forcing a reload of a library: (use :reload :verbose 'introduction) ;; 1.5 Introducing Lancet ;;(krbutil/doc-class clojure.lang.RT) ;;(krbutil/doc-class (class (clojure.lang.RT/baseLoader))) (add-classpath "file:///home/mortis/personal/projects/clojure/lancet/") (use 'lancet) ;; (doseq path (seq (.. clojure.lang.RT baseLoader getURLs)) ;; (println path)) ;; (. (new java.io.File "/home/mortis/personal/projects/clojure/lancet") exists) ;; (. (new java.io.File "/home/mortis/personal/projects/clojure/lancet/lancet") exists) ;; (. (new java.io.File "/home/mortis/personal/projects/clojure/lancet/lancet/lancet.clj") exists) ;; (. (new java.io.File (str "/home/mortis/personal/projects/clojure/lancet/" "lancet/lancet.clj")) exists) ;; (.exists (new java.io.File (str "/home/mortis/personal/projects/clojure/lancet/" "lancet/lancet.clj"))) ;; (.substring "foof" 0 2) (char 65) ;; \A (add-classpath "file:///usr/share/java/ant.jar") (add-classpath "file:///usr/share/java/ant-launcher.jar") (add-classpath "file:///usr/share/java/ant-bootstrap.jar") (use 'lancet.ant) ;; This doesn't seem to work... ;; (def src "src") ;; (def build "classes") ;; (lancet.default-target :compile) ;;(krbutil/doc-class (class (ns-map 'lancet))) (+ 1 (/ 0.00001 1000000000000000)) ;; => 1.0 (+ 1 (/ 0.00001M 1000000000000000)) ;; => 1.00000000000000000001M (class (* 1000 1000 1000)) ;; #=java.lang.Integer (class (* 1000 1000 1000 1000 1000 1000)) ;; #=java.math.BigInteger (/ 22 7) ;; 22/7 (/ 22.0 7) ;; 3.142857142857143 (quot 22 7) ;; 3 (rem 22 7) ;; 1 "this is a\nmultiline string" "this is a multiline string" (= "this is a\nmultiline string" "this is a multiline string") ;; true false (.toUpperCase "foo") (str 1 2 nil 3) ;; "123" (interleave "Attack at midnight." "The purple elephant chortled.") ;; (\A \T \t \h \t \e \a \space \c \p \k \u \space \r \a \p \t \l \space \e \m \space \i \e \d \l \n \e \i \p \g \h \h \a \t \n \. \t) (apply str (interleave "Attack at midnight." "The purple elephant chortled.")) ;; => "ATthtea cpku raptl em iedlneipghhatn.t" (apply str (take-nth 2 "ATthtea cpku raptl em iedlneipghhatn.t")) ;; => "Attack at midnight." (apply str (take-nth 2 (rest "ATthtea cpku raptl em iedlneipghhatn.t"))) ;; "The purple elephant" (class (take-nth 2 "foof")) ;; #=clojure.lang.LazyCons (filter true? [1 1 2 false 3 nil 5]) ;; => nil (true? true) ;; everything else is not true? (false? false) ;; => true (filter identity [1 1 2 false 3 nil 5]) ;; (1 1 2 3 5) (nil? nil) ;; true (class {"a" 1, "b" 2}) ;; #=clojure.lang.PersistentHashMap java.lang.String ;; what is this? (def x 1) #'x ;; #=(var user/x) ;; what's the difference between meta and metadata? ;; ^form => (meta form) ;; #^metadata form => (with-meta form) (string? "hello");; true (keyword? :hello);; true (symbol? :hello);; false (symbol? 'hello);; true (defn greeting "Returns a greeitng of the form 'Hello, name.'" [name] (str "Hello, " name)) (greeting "world") ;; "Hello, world" (doc greeting) (defn date [person1 person2 & chaperones] (println person1 "and" person2 "went out with" (count chaperones) "chaperones.")) (date "Romeo" "Juilet" "Friar Lawrence" "Nurse") ;; Romeo and Juilet went out with 2 chaperones. (defn indexable-word? [word] (> (count word) 2)) ;; (count "foo") ;; (indexable-word? "fo") ;; (indexable-word? "foo") (use 'clojure.contrib.str-utils) (filter indexable-word? (re-split #"\s+" "A fine day it is")) (filter (fn [word] (> (count word) 2)) (re-split #"\s+" "A fine day it is")) (filter #(> (count %1) 2) (re-split #"\s+" "A fine day it is")) (filter #(> (count %) 2) (re-split #"\s+" "A fine day it is")) (defn indexable-words [text] (let [indexable-word? #(> (count %) 2)] (filter indexable-word? (re-split #"\W+" text)))) (indexable-words "A fine day it is") (defn make-greeter [pfx] (fn [name] (str pfx ", " name))) ((make-greeter "Heck!") "Bob") ;; "Heck!, Bob" ;; pg 42 (defn triple [number] (* 3 number)) ;; #=(var user/triple) (defn square-conrners [bottom left width] (let [top (+ bottom width) right (+ left width)] [[bottom left] [top left] [top right] [bottom right]])) (square-conrners 100 100 200) ;; [[100 100] [300 100] [300 300] [100 300]] (def max-grade 100) ;; #=(var user/max-grade) (defn greet-author-1 [author] (println "Hello," (:first-name author))) (greet-author-1 {:last-name "Vinge" :first-name "Vernor"}) ;; Hello, Vernor (defn greet-author [{name :first-name}] (println "Hello," name)) (greet-author {:last-name "Vinge" :first-name "Vernor"}) ;; Hello, Vernor ;; pg 44 - destructuring (let [x [1 2 3]] x) (let [[_ _ x] [1 2 3]] x) (use 'clojure.contrib.str-utils) (defn ellipsize [words] (let [[w1 w2 w3] (re-split #"\s" words)] (str-join " " [w1 w2 w3 "..."]))) (ellipsize "The quick brown fox jumped over the lazy dog.") (re-split #"\s" "The quick brown fox jumped over the lazy dog.") (re-split #"(\s)" "The quick brown fox jumped over the lazy dog.") (resolve 'ellipsize) ;; #=(var user/ellipsize) (resolve 're-split) ;; #=(var clojure.contrib.str-utils/re-split) (ns myapp) (java.io.File/separator) (import '(java.io File)) (File/separator) (clojure.contrib.str-utils/str-join "." [127 0 0 1]) ;; "127.0.0.1" (str-join "." [127 0 0 1]) ;; exception, not in namespace (use 'clojure.contrib.str-utils) ;; ok now, it's in the myapp namespace (str-join "." [127 0 0 1]) ;; "127.0.0.1" ;; force a re-compile/eval (use :reload 'clojure.contrib.str-utils) (ns myapp (use utils clojure.contrib.seq-utils clojure.contrib.str-utils) (import (java.io File))) (find-doc "ns-") (ns user) (resolve 'ellipsize) ;; pg 47 (defn is-small? [number] (if (< number 100) "yes")) (is-small? 99) (is-small? 101) (defn is-small? [number] (if (< number 100) "yes" (do (println "Saw a big number: " number) "no"))) (is-small? 200) ;; Saw a big number: 200 ;; "no" (let [x 1] (println "x is" x) x) (loop [result [] x 5] (if (zero? x) result (recur (conj result x) (dec x)))) (defn countdown [result x] (if (zero? x) result (recur (conj result x) (dec x)))) (countdown [] 5) (into [] (take 5 (iterate dec 5))) (into [] (drop-last (reverse (range 6)))) (apply vector (reverse (rest (range 6)))) ;; loop supports destructuring (loop [[a b] [1 2]] (println (str "a=" a ", b=" b))) ;; page 52 in book v2.0 (def stu {:name "Stu" :email "stu@thinkrelevance.com"}) (def serializable-stu (with-meta stu {:serializable true})) (= stu serializable-stu) ;; true (meta stu) ;; nil (meta serializable-stu) ;; {:serializable true} ^stu ;; nil ^serializable-stu ;; {:serializable true} (def serializable-stu #^{:serializable true} {:name "stu" :email "stu@thinkrelevance.com" }) ^serializable-stu ;; {:serializable true} (def stu-with-address (assoc serializable-stu :state "NC")) ^stu-with-address ;; {:serializable true} (defn shout [#^{:tag String} message] (.toUpperCase message)) (shout 10) ;; **exception** (shout "foof") ;; "FOOF" ;;shorthand for type decl (defn shout [#^String message] (.toUpperCase message)) (shout 10) (shout "foof") ;; (doc subs) ;; (find-doc "methods") (meta #'meta) ;; {:ns #=(find-ns clojure), :file "boot.clj", :arglists ([obj]), :doc "Returns the metadata of obj, returns nil if there is no metadata.", :line 147, :name meta} (def persistent-stu #^{:com.thinkrelevance/persistient true} {:email "stu@thinkrelevance.com", :name "Stu"}) (def persistent-stu #^{:com.thinkrelevance/persistient true} stu) (def persistent-stu (with-meta stu {:com.thinkrelevance/persistient true})) (meta stu) (meta persistent-stu) (add-classpath "file:///home/mortis/misc/software/jakarta/commons-lang-2.4/commons-lang-2.4.jar") (let [args (make-array String 1)] (aset args 0 "qux") (. org.apache.commons.lang.StringUtils (indexOfAny "foo bar qux" args))) (class ["qux"]) (let [args (make-array String 1)] (aset args 0 "qux") (nth args 0)) (defn string-array [& items] (loop [res (make-array String (count items)) items items idx 0] (if (empty? items) res (do (aset res idx (first items)) (recur res (rest items) (+ 1 idx)))))) (defn new-array [type & items] (loop [res (make-array type (count items)) items items idx 0] (if (empty? items) res (do (aset res idx (first items)) (recur res (rest items) (+ 1 idx)))))) (defn pp-array [things] (print (str (.. things getClass getName) "{len=" (count things) ";val=[")) (loop [idx 0] (if (>= idx (count things)) (println "]}") (do (print (str (aget things idx) " ")) (recur (+ 1 idx)))))) ;;(pp-array (new-array String "a" "b" "c")) (defmacro gen-make-array [type] (let [fn-name (str "'" (. (str type) toLowerCase) "-array")] `(defn ~(eval (read-string fn-name)) [& items] (new-array ~type items)))) (macroexpand '(gen-make-array String)) (map (fn [type] (list 'eval `(gen-make-array ~type))) (list String Character Integer)) ((eval (user/gen-make-array #=java.lang.String)) (eval (user/gen-make-array #=java.lang.Character)) (eval (user/gen-make-array #=java.lang.Integer))) (let [type String] `(type ~type)) ;(. java.lang.String (getName)) ;; (let [args (make-array Character 3)] ;; (aset args 0 \q) ;; (aset args 1 \u) ;; (aset args 2 \x) ;; (. org.apache.commons.lang.StringUtils (indexOfAny "foo bar qux" args))) (pr (string-array "foo" "bar" "qux")) ;; heh, into-array is _easier_ (pp-array (into-array (list "foo" "bar" "qux"))) (defn foo [n] (loop [i 1] (if (< i n) (recur (inc i)) i))) (time (foo 10000000)) ;; "Elapsed time: 333.689275 msecs" (defn foo2 [n] (let [ n (int n)] (loop [i (int 1)] (if (< i n) (recur (inc i)) i)))) (time (foo2 10000000)) ;; "Elapsed time: 20.75551 msecs" ;(class (. "foo" charAt 0)) ;;(add-classpath "file:///home/mortis/personal/projects/sandbox/clojure/") (load-file "/home/mortis/personal/projects/sandbox/clojure/krbutil.clj") (krbutil/doc-class String) (krbutil/doc-class "foo") (krbutil/doc-class org.apache.commons.lang.StringUtils) ;;(. org.apache.commons.lang.StringUtils (indexOfAny "foo bar qux" (into-array (list \q \u \x)))) (use 'utils 'clojure.contrib.seq-utils 'clojure.contrib.str-utils) (defn index-of-any [str chars] (some (fn [[idx char]] (and (get chars char) idx)) (indexed str))) (defn index-of-any [str chars] (some (fn [[idx char]] (and (get chars char) idx)) (indexed str))) (index-of-any "aabbccdd" #{\q \u \x \c}) (ancestors (class [1 2 3])) ;; #{#=clojure.lang.Sequential #=clojure.lang.Reversible #=clojure.lang.IPersistentStack #=clojure.lang.IFn #=java.io.Serializable #=clojure.lang.Associative #=clojure.lang.Obj #=java.lang.Comparable #=java.lang.Iterable #=java.util.Collection #=clojure.lang.IPersistentCollection #=java.lang.Object #=clojure.lang.AFn #=java.lang.Runnable #=clojure.lang.APersistentVector #=java.util.concurrent.Callable #=java.util.RandomAccess #=java.util.List #=clojure.lang.IObj #=clojure.lang.IPersistentVector #=java.util.Comparator} ;; pg 56, end of chapter 2 ;; Chapter 3: Working With Java -- pg 60 book v2.0 ;; v2.0 page 61 (def rnd (new java.util.Random)) (.nextInt rnd) (.nextInt rnd 10) ;; (defn random-ints [] ;; (lazy-cons (.nextInt rnd) ;; (random-ints))) ;; (take 10 *random-ints*) (. Math PI);; 3.141592653589793 (.PI Math) ;; 3.141592653589793 (import '(java.util Random Locale)) ;; jscheme style constructor (Random.) Math/PI;;3.141592653589793 (doto (System/getProperties) (setProperty "name" "Stuart") (setProperty "favorite.color" "blue")) ;; book v2.0 pg 65 (seq (make-array String 5)) ;; (nil nil nil nil nil) (to-array ["Easy" "array" "creation"]) ;; #<[Ljava.lang.Object;@ea95e0> (into-array ["Easy" "array" "creation"]) ;; #<[Ljava.lang.String;@19a9d1> ;; multiples of 3 (map #(* % 3) (range 1 12)) ;; (3 6 9 12 15 18 21 24 27 30 33) ;; grab a member function as a clojure function with memfn (map (memfn toUpperCase) ["a" "short" "message"]) ;; ("A" "SHORT" "MESSAGE") (instance? Integer 10) ;; true (import '(javax.crypto Cipher)) (bean (Cipher/getInstance "DES/CBC/PKCS5Padding")) ;; {:algorithm "DES/CBC/PKCS5Padding", :IV nil, :exemptionMechanism nil, :parameters nil, :blockSize 8, :class #=javax.crypto.Cipher, :provider #=(com.sun.crypto.provider.SunJCE. {"Cipher.Blowfish SupportedKeyFormats" "RAW", "AlgorithmParameters.DESede" "com.sun.crypto.provider.DESedeParameters", "AlgorithmParameters.DES" "com.sun.crypto.provider.DESParameters", "Cipher.DES SupportedPaddings" "NOPADDING|PKCS5PADDING|ISO10126PADDING", "AlgorithmParameters.Blowfish" "com.sun.crypto.provider.BlowfishParameters", "Cipher.DESedeWrap SupportedKeyFormats" "RAW", "Alg.Alias.KeyAgreement.1.2.840.113549.1.3.1" "DiffieHellman", "AlgorithmParameterGenerator.DiffieHellman" "com.sun.crypto.provider.DHParameterGenerator", "Cipher.RSA SupportedPaddings" "NOPADDING|PKCS1PADDING|OAEPWITHMD5ANDMGF1PADDING|OAEPWITHSHA1ANDMGF1PADDING|OAEPWITHSHA-1ANDMGF1PADDING|OAEPWITHSHA-256ANDMGF1PADDING|OAEPWITHSHA-384ANDMGF1PADDING|OAEPWITHSHA-512ANDMGF1PADDING", "Alg.Alias.Cipher.TripleDES" "DESede", "Cipher.ARCFOUR SupportedModes" "ECB", "Mac.SslMacSHA1 SupportedKeyFormats" "RAW", "KeyGenerator.DES" "com.sun.crypto.provider.DESKeyGenerator", "Provider.id version" "1.6", "KeyGenerator.DESede" "com.sun.crypto.provider.DESedeKeyGenerator", "Alg.Alias.SecretKeyFactory.PBE" "PBEWithMD5AndDES", "Alg.Alias.KeyFactory.1.2.840.113549.1.3.1" "DiffieHellman", "Mac.HmacSHA1" "com.sun.crypto.provider.HmacSHA1", "Cipher.PBEWithMD5AndDES" "com.sun.crypto.provider.PBEWithMD5AndDESCipher", "Cipher.AES SupportedModes" "ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128", "Cipher.AESWrap SupportedModes" "ECB", "SecretKeyFactory.DESede" "com.sun.crypto.provider.DESedeKeyFactory", "KeyGenerator.SunTlsKeyMaterial" "com.sun.crypto.provider.TlsKeyMaterialGenerator", "AlgorithmParameters.OAEP" "com.sun.crypto.provider.OAEPParameters", "Cipher.AES SupportedKeyFormats" "RAW", "AlgorithmParameters.RC2" "com.sun.crypto.provider.RC2Parameters", "AlgorithmParameters.PBE" "com.sun.crypto.provider.PBEParameters", "Alg.Alias.KeyPairGenerator.DH" "DiffieHellman", "Alg.Alias.KeyAgreement.OID.1.2.840.113549.1.3.1" "DiffieHellman", "Cipher.AES" "com.sun.crypto.provider.AESCipher", "KeyGenerator.RC2" "com.sun.crypto.provider.KeyGeneratorCore$RC2KeyGenerator", "Mac.HmacSHA512" "com.sun.crypto.provider.HmacCore$HmacSHA512", "Provider.id info" "SunJCE Provider (implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, Diffie-Hellman, HMAC)", "Cipher.AES SupportedPaddings" "NOPADDING|PKCS5PADDING|ISO10126PADDING", "Alg.Alias.AlgorithmParameters.OID.1.2.840.113549.1.12.1.6" "PBEWithSHA1AndRC2_40", "Cipher.Blowfish SupportedPaddings" "NOPADDING|PKCS5PADDING|ISO10126PADDING", "Alg.Alias.AlgorithmParameters.OID.1.2.840.113549.1.12.1.3" "PBEWithSHA1AndDESede", "KeyStore.JCEKS" "com.sun.crypto.provider.JceKeyStore", "Cipher.Blowfish SupportedModes" "ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64", "Alg.Alias.SecretKeyFactory.1.2.840.113549.1.5.12" "PBKDF2WithHmacSHA1", "Mac.HmacSHA384 SupportedKeyFormats" "RAW", "Cipher.DESedeWrap" "com.sun.crypto.provider.DESedeWrapCipher", "Cipher.ARCFOUR SupportedPaddings" "NOPADDING", "Alg.Alias.KeyPairGenerator.1.2.840.113549.1.3.1" "DiffieHellman", "Cipher.PBEWithMD5AndTripleDES" "com.sun.crypto.provider.PBEWithMD5AndTripleDESCipher", "Alg.Alias.Cipher.1.2.840.113549.1.12.1.6" "PBEWithSHA1AndRC2_40", "Alg.Alias.Cipher.1.2.840.113549.1.12.1.3" "PBEWithSHA1AndDESede", "Mac.HmacSHA256 SupportedKeyFormats" "RAW", "Alg.Alias.AlgorithmParameterGenerator.1.2.840.113549.1.3.1" "DiffieHellman", "Cipher.PBEWithSHA1AndDESede" "com.sun.crypto.provider.PKCS12PBECipherCore$PBEWithSHA1AndDESede", "SecretKeyFactory.PBEWithMD5AndDES" "com.sun.crypto.provider.PBEKeyFactory$PBEWithMD5AndDES", "KeyPairGenerator.DiffieHellman" "com.sun.crypto.provider.DHKeyPairGenerator", "Cipher.RC2 SupportedModes" "ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64", "Alg.Alias.AlgorithmParameters.Rijndael" "AES", "KeyAgreement.DiffieHellman SupportedKeyClasses" "javax.crypto.interfaces.DHPublicKey|javax.crypto.interfaces.DHPrivateKey", "Mac.HmacMD5 SupportedKeyFormats" "RAW", "KeyGenerator.SunTlsRsaPremasterSecret" "com.sun.crypto.provider.TlsRsaPremasterSecretGenerator", "Cipher.AESWrap SupportedKeyFormats" "RAW", "SecretKeyFactory.DES" "com.sun.crypto.provider.DESKeyFactory", "Cipher.AESWrap SupportedPaddings" "NOPADDING", "Provider.id name" "SunJCE", "KeyGenerator.HmacSHA512" "com.sun.crypto.provider.KeyGeneratorCore$HmacSHA512KG", "Mac.HmacSHA256" "com.sun.crypto.provider.HmacCore$HmacSHA256", "Cipher.ARCFOUR SupportedKeyFormats" "RAW", "Cipher.DES SupportedModes" "ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64", "Cipher.RSA SupportedKeyClasses" "java.security.interfaces.RSAPublicKey|java.security.interfaces.RSAPrivateKey", "SecretKeyFactory.PBEWithMD5AndTripleDES" "com.sun.crypto.provider.PBEKeyFactory$PBEWithMD5AndTripleDES", "Cipher.PBEWithSHA1AndRC2_40" "com.sun.crypto.provider.PKCS12PBECipherCore$PBEWithSHA1AndRC2_40", "AlgorithmParameters.DiffieHellman" "com.sun.crypto.provider.DHParameters", "Mac.HmacMD5" "com.sun.crypto.provider.HmacMD5", "Cipher.RSA" "com.sun.crypto.provider.RSACipher", "Mac.SslMacMD5" "com.sun.crypto.provider.SslMacCore$SslMacMD5", "Alg.Alias.AlgorithmParameters.OID.1.2.840.113549.1.5.3" "PBEWithMD5AndDES", "Cipher.DESede SupportedPaddings" "NOPADDING|PKCS5PADDING|ISO10126PADDING", "Alg.Alias.AlgorithmParameterGenerator.OID.1.2.840.113549.1.3.1" "DiffieHellman", "Cipher.DESede" "com.sun.crypto.provider.DESedeCipher", "Alg.Alias.AlgorithmParameters.OID.1.2.840.113549.1.3.1" "DiffieHellman", "Alg.Alias.AlgorithmParameters.1.2.840.113549.1.5.3" "PBEWithMD5AndDES", "Mac.HmacSHA512 SupportedKeyFormats" "RAW", "Mac.HmacPBESHA1 SupportedKeyFormats" "RAW", "Alg.Alias.AlgorithmParameterGenerator.DH" "DiffieHellman", "Cipher.DESedeWrap SupportedPaddings" "NOPADDING", "Alg.Alias.SecretKeyFactory.OID.1.2.840.113549.1.5.12" "PBKDF2WithHmacSHA1", "Alg.Alias.AlgorithmParameters.1.2.840.113549.1.3.1" "DiffieHellman", "Mac.HmacPBESHA1" "com.sun.crypto.provider.HmacPKCS12PBESHA1", "Cipher.DES SupportedKeyFormats" "RAW", "AlgorithmParameters.PBEWithMD5AndTripleDES" "com.sun.crypto.provider.PBEParameters", "Cipher.DESedeWrap SupportedModes" "CBC", "Alg.Alias.KeyFactory.OID.1.2.840.113549.1.3.1" "DiffieHellman", "Alg.Alias.Cipher.OID.1.2.840.113549.1.5.3" "PBEWithMD5AndDES", "AlgorithmParameters.AES" "com.sun.crypto.provider.AESParameters", "Alg.Alias.AlgorithmParameters.TripleDES" "DESede", "Alg.Alias.SecretKeyFactory.TripleDES" "DESede", "KeyGenerator.HmacSHA256" "com.sun.crypto.provider.KeyGeneratorCore$HmacSHA256KG", "Alg.Alias.KeyGenerator.TripleDES" "DESede", "Alg.Alias.AlgorithmParameters.DH" "DiffieHellman", "KeyGenerator.AES" "com.sun.crypto.provider.AESKeyGenerator", "Cipher.RC2 SupportedPaddings" "NOPADDING|PKCS5PADDING|ISO10126PADDING", "Alg.Alias.Cipher.RC4" "ARCFOUR", "Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.3.1" "DiffieHellman", "Mac.HmacSHA384" "com.sun.crypto.provider.HmacCore$HmacSHA384", "SecretKeyFactory.PBKDF2WithHmacSHA1" "com.sun.crypto.provider.PBKDF2HmacSHA1Factory", "Provider.id className" "com.sun.crypto.provider.SunJCE", "Cipher.DES" "com.sun.crypto.provider.DESCipher", "Cipher.Blowfish" "com.sun.crypto.provider.BlowfishCipher", "KeyGenerator.SunTlsMasterSecret" "com.sun.crypto.provider.TlsMasterSecretGenerator", "KeyGenerator.HmacSHA1" "com.sun.crypto.provider.HmacSHA1KeyGenerator", "Alg.Alias.SecretKeyFactory.1.2.840.113549.1.5.3" "PBEWithMD5AndDES", "KeyGenerator.SunTlsPrf" "com.sun.crypto.provider.TlsPrfGenerator", "SecretKeyFactory.PBEWithSHA1AndDESede" "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndDESede", "KeyGenerator.ARCFOUR" "com.sun.crypto.provider.KeyGeneratorCore$ARCFOURKeyGenerator", "Alg.Alias.KeyAgreement.DH" "DiffieHellman", "Alg.Alias.KeyGenerator.Rijndael" "AES", "AlgorithmParameters.PBEWithSHA1AndDESede" "com.sun.crypto.provider.PBEParameters", "Alg.Alias.KeyGenerator.RC4" "ARCFOUR", "Alg.Alias.Cipher.OID.1.2.840.113549.1.12.1.6" "PBEWithSHA1AndRC2_40", "Alg.Alias.Cipher.OID.1.2.840.113549.1.12.1.3" "PBEWithSHA1AndDESede", "Mac.SslMacMD5 SupportedKeyFormats" "RAW", "Mac.HmacSHA1 SupportedKeyFormats" "RAW", "Cipher.DESede SupportedKeyFormats" "RAW", "Cipher.RC2" "com.sun.crypto.provider.RC2Cipher", "SecretKeyFactory.PBEWithSHA1AndRC2_40" "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC2_40", "KeyGenerator.HmacMD5" "com.sun.crypto.provider.HmacMD5KeyGenerator", "AlgorithmParameters.PBEWithSHA1AndRC2_40" "com.sun.crypto.provider.PBEParameters", "KeyGenerator.HmacSHA384" "com.sun.crypto.provider.KeyGeneratorCore$HmacSHA384KG", "Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.6" "PBEWithSHA1AndRC2_40", "KeyFactory.DiffieHellman" "com.sun.crypto.provider.DHKeyFactory", "Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.3" "PBEWithSHA1AndDESede", "AlgorithmParameters.PBEWithMD5AndDES" "com.sun.crypto.provider.PBEParameters", "Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.6" "PBEWithSHA1AndRC2_40", "Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.3" "PBEWithSHA1AndDESede", "Cipher.AESWrap" "com.sun.crypto.provider.AESWrapCipher", "Alg.Alias.SecretKeyFactory.OID.1.2.840.113549.1.5.3" "PBEWithMD5AndDES", "Alg.Alias.Cipher.Rijndael" "AES", "Cipher.RSA SupportedModes" "ECB", "Cipher.DESede SupportedModes" "ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64", "Alg.Alias.SecretKeyFactory.OID.1.2.840.113549.1.12.1.6" "PBEWithSHA1AndRC2_40", "Alg.Alias.SecretKeyFactory.OID.1.2.840.113549.1.12.1.3" "PBEWithSHA1AndDESede", "Cipher.ARCFOUR" "com.sun.crypto.provider.ARCFOURCipher", "Alg.Alias.Cipher.1.2.840.113549.1.5.3" "PBEWithMD5AndDES", "Mac.SslMacSHA1" "com.sun.crypto.provider.SslMacCore$SslMacSHA1", "KeyAgreement.DiffieHellman" "com.sun.crypto.provider.DHKeyAgreement", "Cipher.RC2 SupportedKeyFormats" "RAW", "Alg.Alias.KeyFactory.DH" "DiffieHellman", "KeyGenerator.Blowfish" "com.sun.crypto.provider.BlowfishKeyGenerator"})} (:blockSize (bean (Cipher/getInstance "DES/CBC/PKCS5Padding"))) ;; 8 (defn sum-to [n] (loop [i 1 sum 0] (if (<= i n) (recur (inc i) (+ i sum)) sum))) (sum-to 10) (dotimes _ 5 (time (sum-to 10000))) ;; "Elapsed time: 1.952158 msecs" ;; "Elapsed time: 0.631982 msecs" ;; "Elapsed time: 0.63262 msecs" ;; "Elapsed time: 1.705838 msecs" ;; "Elapsed time: 0.686695 msecs" (defn integer-sum-to [n] (let [n (int n)] (loop [i (int 0) sum (int 0)] (if (<= i n) (recur (inc i) (+ i sum)) sum)))) (dotimes _ 5 (time (integer-sum-to 10000))) ;; "Elapsed time: 0.065024 msecs" ;; "Elapsed time: 0.039301 msecs" ;; "Elapsed time: 0.039163 msecs" ;; "Elapsed time: 0.031015 msecs" ;; "Elapsed time: 0.031015 msecs" (defn unchecked-integer-sum-to [n] (let [n (int n)] (loop [i (int 0) sum (int 0)] (if (<= i n) (recur (inc i) (unchecked-add i sum)) sum)))) (dotimes _ 5 (time (unchecked-integer-sum-to 10000))) ;; "Elapsed time: 0.049013 msecs" ;; "Elapsed time: 0.031264 msecs" ;; "Elapsed time: 0.031065 msecs" ;; "Elapsed time: 0.030986 msecs" ;; "Elapsed time: 0.030994 msecs" (defn better-sum-to [n] (reduce + (range 1 (inc n)))) (dotimes _ 5 (time (better-sum-to 10000))) ;; "Elapsed time: 0.562023 msecs" ;; "Elapsed time: 6.761603 msecs" ;; "Elapsed time: 0.601324 msecs" ;; "Elapsed time: 0.515199 msecs" ;; "Elapsed time: 1.694504 msecs" (defn best-sum-to [n] (/ (* n (inc n)) 2)) (dotimes _ 5 (time (best-sum-to 10000))) ;; "Elapsed time: 0.032329 msecs" ;; "Elapsed time: 0.003667 msecs" ;; "Elapsed time: 0.003463 msecs" ;; "Elapsed time: 0.003452 msecs" ;; "Elapsed time: 0.003422 msecs" (defn describe-class [c] {:name (.getName c) :final (java.lang.reflect.Modifier/isFinal (.getModifiers c)) }) (set! *warn-on-reflection* true) ;; then re-eval describe-class and you'll see the following in the *inferior-lisp* buffer: ;; Reflection warning, line: 3 - reference to field getModifiers can't be resolved. ;; Reflection warning, line: 2 - reference to field getName can't be resolved. (defn describe-class [#^Class c] {:name (.getName c) :final (java.lang.reflect.Modifier/isFinal (.getModifiers c)) }) (describe-class StringBuilder) (describe-class "foo");; error ;; HERE stopped in book v2.0 at section 3.3 Calling Clojure from Java (import '(org.xml.sax InputSource) '(org.xml.sax.helpers DefaultHandler) '(java.io StringReader) '(javax.xml.parsers SAXParserFactory)) (def print-element-handler (proxy [DefaultHandler] [] (startElement [qname, local, qname, attrs] (println (format "Saw element: %s" qname))))) print-element-handler ;; # (class print-element-handler) ;; #=clojure.lang.Proxy__3473 (defn demo-sax-parser [source handler] (.. SAXParserFactory newInstance newSAXParser (parse (InputSource. (StringReader. source)) handler))) (demo-sax-parser " body of bar body of qux " print-element-handler) ;; Saw element: foo ;; Saw element: bar ;; Saw element: qux (.start (Thread. (proxy [Runnable] [] (run [] (println "I ran!"))))) ;; functions implement runnable and callable (#(println "foo")) ;; foo (.run #(println "foo")) ;; foo (.call #(println "foo")) ;; foo ;; cool, this works too: (.start (Thread. #(println "foo"))) ;; functions are callable/runnable: (dotimes ii 5 (.start (Thread. (fn [] (Thread/sleep (rand 1000)) (println (format "Finished %d on %s" ii (Thread/currentThread))))))) ;; page 75 book v2.0 ;; Creating Java Classes (add-classpath "file:///home/mortis/misc/software/java/junit-4.5.jar") (add-classpath "file:///home/mortis/personal/projects/clojure/sandbox") (gen-and-save-class "/home/mortis/personal/projects/clojure/sandbox" "test.WidgetTest" :extends junit.framework.TestCase :methods [ ["testOne" [] (Void/TYPE)] ["testFour" [] (Void/TYPE)] ;; ["testTwo" [] (Void/TYPE)] ]) ;; at this point, I created the test/WidgetTest.clj ;; but I can't get the gen-and-save-class to work w/the external runner ;;; export CLOJURE_JAR="$HOME/personal/projects/clojure/clojure.org/clojure/trunk/clojure.jar" ;;; export CONTRIB_JAR="$HOME/personal/projects/clojure/clojure.org/clojure-contrib/clojure-contrib/trunk/clojure-contrib.jar" ;;; export CLOJURE_CLASSPATH="$CLOJURE_JAR:$CONTRIB_JAR:$HOME/.clojure/*:$HOME/misc/software/clojure/programming-clojure/code" ;;; java -cp $CLOJURE_CLASSPATH:/home/mortis/misc/software/java/junit-4.5.jar:. junit.textui.TestRunner test.WidgetTest ;; so I'm giving up and moving on to... ;; 3.4 Exception Handling page 77 book v2.0 (try (throw (Exception. "something failed")) (catch Exception e (println (format "oops: %s" e))) (finally (println "cleanup goes here"))) ;; 3.5 Adding And Projects and Tasks to Lancet (do (add-classpath "file:///usr/share/java/ant.jar") (add-classpath "file:///usr/share/java/ant-launcher.jar") (add-classpath "file:///usr/share/java/ant-bootstrap.jar")) (def mkdir-task (org.apache.tools.ant.taskdefs.Mkdir.)) (krbutil/doc-class mkdir-task) (.execute mkdir-task) ;; boom! (bean mkdir-task) ;; {:runtimeConfigurableWrapper #, :owningTarget nil, :taskType nil, :taskName nil, :class #=org.apache.tools.ant.taskdefs.Mkdir, :location #<>, :project nil, :description nil} (filter #(= "setDir" (.getName %)) (.getMethods (class mkdir-task))) ;; (#) (.setDir mkdir-task (java.io.File. "sample-dir")) (.execute mkdir-task) ;; Created dir: /home/mortis/sample-dir (def project (org.apache.tools.ant.Project.)) (def logger (org.apache.tools.ant.NoBannerLogger.)) (krbutil/doc-class logger) (def #^{:doc "Dummy Ant project to keep Ant tasks happy."} ant-project (let [proj (org.apache.tools.ant.Project.) logger (org.apache.tools.ant.NoBannerLogger.)] (doto logger (setMessageOutputLevel org.apache.tools.ant.Project/MSG_INFO) (setOutputPrintStream System/out) (setErrorPrintStream System/err)) (doto proj (init) (addBuildListener logger)) proj)) ant-project ;; # (keys (bean ant-project)) ;; (:coreLoader :keepGoingMode :filters :properties :taskDefinitions :globalFilterSet :defaultTarget :executor :baseDir :class :inputHandler :userProperties :dataTypeDefinitions :references :defaultInputStream :buildListeners :description :targets :name) (:userProperties (bean ant-project)) ;; #=(java.util.Hashtable. {}) (:baseDir (bean ant-project)) ;;# (class (:properties (bean ant-project))) ;; #=java.util.Hashtable (krbutil/doc-class (:properties (bean ant-project))) (.size (:properties (bean ant-project))) ;; 53 (def echo-task (.createTask ant-project "echo")) (.setMessage echo-task "hello ant") (.execute echo-task) ;; [echo] hello ant ;; nice! (defn instantiate-task [project name] (let [task (.createTask project name)] (doto task (init) (setProject project)) task)) (instantiate-task ant-project "echo") ;; ah, but since doto is an aprog1, we don't need the let, this is shorter (defn instantiate-task [project name] (doto (.createTask project name) (init) (setProject project))) (def echo-task (instantiate-task ant-project "echo")) (.setMessage echo-task "echo from instantiate task") (.execute echo-task) ;; [echo] echo from instantiate task (instantiate-task ant-project "foof") (defn instantiate-task [project name] (let [task (.createTask project name)] (if (nil? task) (throw (Exception. (format "No task named '%s'" name)))) (doto task (init) (setProject project)))) (instantiate-task ant-project "foof") ;; page 86 book v2.0 ;; Chapter 4: Unifying Data with Sequences ;; diversion, just for fun, the SICP example of defining cons/car/cdr ;; using no storage except closures: ;; (defn mycons [a b] ;; (fn [arg] ;; (if arg a b))) ;; (defn mycar [cell] ;; (cell true)) ;; (defn mycdr [cell] ;; (cell false)) ;; (mycar (mycons 1 2)) ;; (mycdr (mycons 1 2)) ;; heh, consing onto an array converts it into a list: (class (cons 0 [1 2 3])) ;; #=clojure.lang.Cons ;; same w/rest? (class (rest [1 2 3])) ;; #=clojure.lang.APersistentVector$Seq (first {:fname "Kyle" :lname "Burton"}) ;; [:fname "Kyle"] (first {:languages ["Clojure" "Perl"] :gender "M" :age 38 :lname "Burton" :name "Kyle" }) ;; [:age 38] ;; NB: these typeconvert: (rest {:languages ["Clojure" "Perl"] :gender "M" :age 38 :lname "Burton" :name "Kyle" }) ;; ([:gender "M"] [:languages ["Clojure" "Perl"]] [:lname "Burton"] [:name "Kyle"]) (cons [:nickname "Chet"] {:languages ["Clojure" "Perl"] :gender "M" :age 38 :lname "Burton" :name "Kyle" }) ;; ([:nickname "Chet"] [:age 38] [:gender "M"] [:languages ["Clojure" "Perl"]] [:lname "Burton"] [:name "Kyle"]) (first #{:a :b :c}) ;; :a (rest #{:a :b :c}) ;; (:c :b) (cons :d #{:a :b :c}) ;; (:d :a :c :b) (sorted-set :a :b :c :d) ;; #{:a :b :c :d} (cons :e (sorted-set :a :b :c :d)) ;; (:e :a :b :c :d) (class (cons :e (sorted-set :a :b :c :d))) ;; #=clojure.lang.Cons (sorted-map :languages ["Clojure" "Perl"] :gender "M" :age 38 :lname "Burton" :name "Kyle") ;; {:age 38, :gender "M", :languages ["Clojure" "Perl"], :lname "Burton", :name "Kyle"} ;; into is append? (into [1 2 3] [4 5 6]) ;; [1 2 3 4 5 6] ;; YES! ;; reverse the words in "I am cold" ;; (apply str (interpose " " (reverse (.split "I am cold" " ")))) ;; page 91 book v2.0 (doseq ii (take 128 (iterate (fn [x] (* x 2)) 1)) (println (count (format "%d" ii)))) ;; 4.2 Using the Sequence Library (range 10) ;;(0 1 2 3 4 5 6 7 8 9) (range 10 20) ;; (10 11 12 13 14 15 16 17 18 19) (range 0 105 5) ;; (0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100) (replicate 20 'a) ;; (a a a a a a a a a a a a a a a a a a a a) (replicate 2 10) ;; (10 10) (replicate 10 "x") ;; ("x" "x" "x" "x" "x" "x" "x" "x" "x" "x") ;; this is all positive the integers... (take 10 (iterate inc 1)) ;; (1 2 3 4 5 6 7 8 9 10) (def whole-numbers (iterate inc 1)) ;; careful, repeate, unlike repeate, is infinite... (take 20 (repeat 1)) ;; (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1) ;; awesome :) (take 10 (cycle (range 3))) ;; (0 1 2 0 1 2 0 1 2 0) ;; nice! (take 10 (cycle '(a b c))) ;; (a b c a b c a b c a) (interleave '(a b c) '(1 2 3)) ;;(a 1 b 2 c 3) (take 10 (interleave whole-numbers (repeat 'a))) ; (1 a 2 a 3 a 4 a 5 a) ;; you can mix infinite and finite... (interleave whole-numbers (seq (.split "this is a string" ""))) ;; (1 "" 2 "t" 3 "h" 4 "i" 5 "s" 6 " " 7 "i" 8 "s" 9 " " 10 "a" 11 " " 12 "s" 13 "t" 14 "r" 15 "i" 16 "n" 17 "g") (apply str (take 19 (interpose "," whole-numbers))) ;; "1,2,3,4,5,6,7,8,9,10" (interpose "," ["apples" "bananas" "grapes"]) ;; ("apples" "," "bananas" "," "grapes") (apply str (interpose "," ["apples" "bananas" "grapes"])) ;; "apples,bananas,grapes" (use 'clojure.contrib.str-utils) (str-join ", " (take 20 whole-numbers)) ;; "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20" (list 'a 'b 'c) ;; (a b c) (vector 'a 'b 'c) ;; [a b c] (set ['a 'b 'c]) ;; #{a c b} (hash-map :a 1 :b 2 :c 3) ;; {:a 1, :c 3, :b 2} (take 100 (filter odd? whole-numbers)) ;; (1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97 99 101 103 105 107 109 111 113 115 117 119 121 123 125 127 129 131 133 135 137 139 141 143 145 147 149 151 153 155 157 159 161 163 165 167 169 171 173 175 177 179 181 183 185 187 189 191 193 195 197 199) (take-while (fn [x] (< x 22)) whole-numbers) ;;(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21) ;; huh, a hash-set can be used as a function, which tests for membership (take-while (complement #{\a\e\i\o\u}) "the-quick-brown-fox") ;; (\t \h) (#{\a\e\i\o\u} \x) ;; nil (#{\a\e\i\o\u} \a) ;; \a (take 20 (drop-while (fn [x] (< x 22)) whole-numbers)) ;; (22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41) (drop-while (complement #{\a\e\i\o\u}) "the-quick-brown-fox") ;; (\e \- \q \u \i \c \k \- \b \r \o \w \n \- \f \o \x) (apply str (drop-while (complement #{\a\e\i\o\u}) "the-quick-brown-fox")) ;; "e-quick-brown-fox" (split-at 5 (take 20 whole-numbers)) ;; [(1 2 3 4 5) (6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)] (split-with #(<= % 10) (range 0 20 2)) ;; [(0 2 4 6 8 10) (12 14 16 18)] (every? even? (range 1 10 2)) ;; false (every? odd? (range 1 10 2)) ;; true (some even? (range 1 10 2)) ;; nil (some odd? (range 1 10 2)) ;; true (some identity [nil false 1 nil 2]) ;; 1 (not-every? even? (range 1 10)) ;; true (not-any? even? (range 1 10 2)) ;; true (map #(format "

%s

" %) ["the" "quick" "brown" "fox"]) ;; ("

the

" "

quick

" "

brown

" "

fox

") (reduce + (range 1 11)) ;; 55 (defn sum-nums-upto [nn] (/ (* nn (- nn 1)) 2)) (sum-nums-upto 11) ;; 55 (sum-nums-upto 100) ;; 4950 ;; er, 4950 is the same as the n-choose2 of 100...are these 2 algorithims related? Can't be... (map sum-nums-upto (range 1 10)) ;; (0 1 3 6 10 15 21 28 36) (reduce * (range 1 11)) ;; 3628800 ;; book v2.0 page 98 list comprehensions... (for [word (.split "The quick brown fox" " ")] (format "

%s

" word)) ;; ("

The

" "

quick

" "

brown

" "

fox

") (take 10 (for [n whole-numbers :when (even? n)] n)) ;; (2 4 6 8 10 12 14 16 18 20) ;; generate all the positions on a chess board: (for [file "ABCDEFGH" rank (range 1 9)] (format "%c%d" file rank)) ;; ("A1" "A2" "A3" "A4" "A5" "A6" "A7" "A8" "B1" "B2" "B3" "B4" "B5" "B6" "B7" "B8" "C1" "C2" "C3" "C4" "C5" "C6" "C7" "C8" "D1" "D2" "D3" "D4" "D5" "D6" "D7" "D8" "E1" "E2" "E3" "E4" "E5" "E6" "E7" "E8" "F1" "F2" "F3" "F4" "F5" "F6" "F7" "F8" "G1" "G2" "G3" "G4" "G5" "G6" "G7" "G8" "H1" "H2" "H3" "H4" "H5" "H6" "H7" "H8") (count (for [file "ABCDEFGH" rank (range 1 9)] (format "%c%d" file rank))) ;;64 ;; the pythagorean triples example: (for [aa (range 1 10) bb (range 1 10) cc (range 1 10) :when (= (* cc cc) (+ (* aa aa) (* bb bb)))] (list aa bb cc)) ;; ((3 4 5) (4 3 5)) ;; ok, so how do we do all permutations? (defn all-permutations [things] (if (= 1 (count things)) (list things) (for [head things tail (all-permutations (disj (set things) head))] (do (cons head tail))))) (all-permutations '(a b c)) ;; ((a c b) (a b c) (b a c) (b c a) (c a b) (c b a)) ;; (remove #(= % 'a) '(a b c)) ;; 4.3 Lazy and Infinite Sequences (class (lazy-cons 0 [1 2 3])) ;; #=clojure.lang.LazyCons (lazy-cat [-3 -2 -1] [0] [1 2 3]) ;; (-3 -2 -1 0 1 2 3) (concat [1 2 3] '(4 5 6)) ;; (1 2 3 4 5 6) ;; Forcing sequences book v2.0, page 100 (def x (for [i (range 1 3)] (do (println i) i))) (doall x) (def x (for [i (range 1 3)] (do (println i) i))) ;; dorun doesn't cons up its results, it just traverses the seq (dorun x) ;; Chapter 4.4, Clojure Makes Java Seq-able book v2.0 page 101 (first (.getBytes "Hello")) ;; 72 (rest (.getBytes "Hello")) ;; (101 108 108 111) (cons 72 (.getBytes "ello")) ;; (72 101 108 108 111) (krbutil/doc-class String) (class (.getBytes "Hello")) ;; #=(java.lang.Class/forName "[B") (map class (cons 72 (.getBytes "ello"))) ;; (#=java.lang.Integer #=java.lang.Byte #=java.lang.Byte #=java.lang.Byte #=java.lang.Byte) (krbutil/doc-class Byte) (into-array (seq (cons (.byteValue 72) (.getBytes "ello")))) ;; #<[Ljava.lang.Byte;@1e651b0> ;; ok, this doens't work, so how would you call the string constuctor ;; out of the byte array to get back a string? '(new String (into-array Byte (cons (.byteValue 72) (.getBytes "ello")))) (new String "foo") (first (System/getProperties)) ;; # (class (first (System/getProperties))) ;; #=java.util.Hashtable$Entry (first "Hello") ;; \H (apply str (reverse "Hello")) ;; "olleH" ;; page 103 book v2.0 (re-seq #"\w+" "the quick brown fox") ;; ("the" "quick" "brown" "fox") (sort (re-seq #"\w+" "the quick brown fox")) ;; ("brown" "fox" "quick" "the") (drop 2 (re-seq #"\w+" "the quick brown fox")) ;; ("brown" "fox") (map #(.toUpperCase %) (re-seq #"\w+" "The quick brown fox.")) ;; ("THE" "QUICK" "BROWN" "FOX") (import '( java.io File)) (.listFiles (File. ".")) ;; #<[Ljava.io.File;@e48504> (seq (.listFiles (File. "."))) ;; (#<./.viminfo> #<./test.scm> #<./cover_db> #<./test.rb> #<./Pictures> #<./elunit.el_files> #<./Documents> #<./personal> #<./.ICEauthority> #<./foo.png> #<./.slime-history.eld> #<./foo.c~> #<./bin> #<./wh-userpic.png> #<./.gconf> #<./.gtkrc-2.0-kde> #<./.ktorrent.lock> #<./.gqview> #<./.DCOPserver_indigo64__0> #<./oscon-2008.tar.gz> #<./.emacs> #<./.emacs.lib> #<./.qt> #<./.mozilla> #<./test.mdb> #<./.emacs~> #<./.kde> #<./local> #<./foo.c> #<./.recently-used.xbel> #<./.Xauthority> #<./.bashrc> #<./.config> #<./.mplayer> #<./.pulse-cookie> #<./.xcompmgrrc> #<./.gconfd> #<./.openoffice.org2> #<./.thumbnails> #<./.subversion> #<./.bash_history> #<./.gimp-2.4> #<./.emacs.bmk> #<./x.html> #<./.DCOPserver_indigo64_:0> #<./git.el> #<./.fonts.conf> #<./.sinan> #<./test.rb~> #<./test2.mdb> #<./.mcop> #<./.sudo_as_admin_successful> #<./Videos> #<./Music> #<./.dmrc> #<./me.png> #<./.fonts> #<./.bash_logout> #<./confs.txt> #<./HMS.pcf> #<./.fullcircle> #<./.ssh> #<./.xine> #<./TODO> #<./Foo.class> #<./.pulse> #<./.screenrc> #<./wh-userpic-112x128.png> #<./.emacs.d> #<./misc> #<./.recently-used> #<./vc-git.el> #<./Foo.java> #<./.adobe> #<./.macromedia> #<./.gtk_qt_engine_rc> #<./.profile> #<./Desktop> #<./backups> #<./.smplayer> #<./elunit.el> #<./.local> #<./git-blame.el> #<./.lesshst> #<./.krb-bash-fns> #<./a.out> #<./.dictrc> #<./.xsession-errors> #<./Public> #<./foo.txt> #<./tmp> #<./.fontconfig> #<./foo.jpg> #<./test> #<./Templates> #<./mailman.lisp>) (map (memfn getName) (seq (.listFiles (File. ".")))) ;; (".viminfo" "test.scm" "cover_db" "test.rb" "Pictures" "elunit.el_files" "Documents" "personal" ".ICEauthority" "foo.png" ".slime-history.eld" "foo.c~" "bin" "wh-userpic.png" ".gconf" ".gtkrc-2.0-kde" ".ktorrent.lock" ".gqview" ".DCOPserver_indigo64__0" "oscon-2008.tar.gz" ".emacs" ".emacs.lib" ".qt" ".mozilla" "test.mdb" ".emacs~" ".kde" "local" "foo.c" ".recently-used.xbel" ".Xauthority" ".bashrc" ".config" ".mplayer" ".pulse-cookie" ".xcompmgrrc" ".gconfd" ".openoffice.org2" ".thumbnails" ".subversion" ".bash_history" ".gimp-2.4" ".emacs.bmk" "x.html" ".DCOPserver_indigo64_:0" "git.el" ".fonts.conf" ".sinan" "test.rb~" "test2.mdb" ".mcop" ".sudo_as_admin_successful" "Videos" "Music" ".dmrc" "me.png" ".fonts" ".bash_logout" "confs.txt" "HMS.pcf" ".fullcircle" ".ssh" ".xine" "TODO" "Foo.class" ".pulse" ".screenrc" "wh-userpic-112x128.png" ".emacs.d" "misc" ".recently-used" "vc-git.el" "Foo.java" ".adobe" ".macromedia" ".gtk_qt_engine_rc" ".profile" "Desktop" "backups" ".smplayer" "elunit.el" ".local" "git-blame.el" ".lesshst" ".krb-bash-fns" "a.out" ".dictrc" ".xsession-errors" "Public" "foo.txt" "tmp" ".fontconfig" "foo.jpg" "test" "Templates" "mailman.lisp") (count (file-seq (File. "."))) ;; 77783 (count (map (memfn getName) (.listFiles (File. ".")))) ;; 96 (defn minutes [mins] (* mins 1000 60)) (defn recently-modified? [file] (> (.lastModified file) (- (System/currentTimeMillis) (minutes 30)))) (filter recently-modified? (file-seq (File. "."))) ;; pwd cwd (.getAbsolutePath (File. ".")) ;;"/home/mortis/." (add-classpath "file:///home/mortis/personal/projects/clojure/clojure.org/clojure-contrib/clojure-contrib/trunk/src/clojure/contrib/") (require 'duck-streams) ;; book v2.0 page 105 ;; bleh, I wish there was a __FILE__, oh, there is a *file*, but it doesn't work in slime/the-repl :( (take 2 (line-seq (clojure.contrib.duck-streams/reader (krbutil/expand-file-name "~/personal/projects/clojure/sandbox/test.clj")))) ;; ("(defmulti blank? class)" "(defmethod blank? String [s] (every? #{\\space} s))") ;; this doesn't work - I think I'm in limbo wrt the version of ;; core-clojre and clojure-contrib ;; (use 'clojure.contrib.duck-streams/reader) (defn non-blank? [line] (and (re-find #"\S" line) true)) (defn non-svn? [file] (not (.startsWith (.toString file) ".svn"))) (defn clojure-source? [file] (.endsWith (.toString file) ".clj")) ;; with-open doens't like the reader form? (defn clojure-loc [base-file] (reduce + (for [file (file-seq base-file) :when (and (clojure-source? file) (non-svn? file))] (with-open [rdr (clojure.contrib.duck-streams/reader file)] (count (filter non-blank? (line-seq rdr))))))) (with-open [rdr (clojure.contrib.duck-streams/reader (krbutil/expand-file-name "~/personal/projects/clojure/sandbox/test.clj"))] (take 2 (line-seq rdr))) (def reader clojure.contrib.duck-streams/reader) (take 2 (line-seq (reader (krbutil/expand-file-name "~/personal/projects/clojure/sandbox/test.clj")))) (with-open [rdr (reader (krbutil/expand-file-name "~/personal/projects/clojure/sandbox/test.clj"))] (take 2 (line-seq rdr))) ;; :( don't know how to get this to work, must be my borked versions ;; of clojure an clojure-contrib... (with-open [rdr (reader nil)] (set! rdr (krbutil/expand-file-name "~/personal/projects/clojure/sandbox/test.clj")) (take 2 (line-seq rdr))) ;; for now, just don't use with-open, which is a bummer...but oh well (defn clojure-loc [base-file] (reduce + (for [file (file-seq base-file) :when (and (clojure-source? file) (non-svn? file))] (count (filter non-blank? (line-seq (clojure.contrib.duck-streams/reader file))))))) (clojure-loc (java.io.File. (krbutil/expand-file-name "~/personal/projects/clojure"))) ;; 10156 ;; HERE book v2.0 page 106 Seq-ing XML (use 'clojure.xml) ;; (.exists (File. (krbutil/expand-file-name "~/personal/projects/clojure/sandbox/compositions.xml"))) (xml-seq (parse (File. (krbutil/expand-file-name "~/personal/projects/clojure/sandbox/compositions.xml")))) (for [x (xml-seq (parse (File. (krbutil/expand-file-name "~/personal/projects/clojure/sandbox/compositions.xml")))) :when (= :composition (:tag x))] (:composer (:attrs x))) ; ("J. S. Bach" "J. S. Bach" "W. A. Mozart") ;;; 4.5 Calling Strucutre-Specific Functions (peek [1 2 3 4]) ;; 4 ;; pop is like rest... (pop [1 2 3 4]) ;; [1 2 3] (rest ()) ;;nil (pop ()) ;; *boom* (keys {:a 1 :b 2 :c 3}) ;; (:a :c :b) (vals {:a 1 :b 2 :c 3}) ;; (1 3 2) (get {:a 1 :b 2 :c 3} :a) ;; 1 (get {:a 1 :b 2 :c 3} :x) ;; nil ;; maps can be treated as functions - equiv to a get of the key ({:a 1 :b 2 :c 3} :a) ;; 1 ({:a 1 :b 2 :c 3} :x) ;; nil ;; keywords are also functions, so they work the same way (to extract ;; a value from a map): (:a {:a 1 :b 2 :c 3}) ;; 1 (:x {:a 1 :b 2 :c 3}) ;; nil (map (partial contains? {:a 1 :b 2 :c 3}) (list :a :b :c :x)) ;; (true true true false) (let [score {:stu nil :joey 100}] (println (:stu score)) (println (contains? score :stu))) ;; nil ;; true (def song {:name "Angus Dei" :artist "Krzysztof Penderecki" :album "Polish Requiem" :genre "Classical"}) (assoc song :kind "MPEG Audio File") ;; {:album "Polish Requiem", :artist "Krzysztof Penderecki", :genre "Classical", :kind "MPEG Audio File", :name "Angus Dei"} (dissoc song :genre) ;; {:album "Polish Requiem", :artist "Krzysztof Penderecki", :name "Angus Dei"} (select-keys song [:name :artist]) ;; {:artist "Krzysztof Penderecki", :name "Angus Dei"} (merge song {:size 8118166 :time 507245}) ;; {:album "Polish Requiem", :size 8118166, :artist "Krzysztof Penderecki", :genre "Classical", :time 507245, :name "Angus Dei"} (doc merge) (merge {:a 1 :b 1} {:b 2} song) ;; {:album "Polish Requiem", :a 1, :artist "Krzysztof Penderecki", :genre "Classical", :b 2, :name "Angus Dei"} (merge-with concat {:rubble ["Barney"], :flintstone ["Fred"]} {:rubble ["Betty"], :flintstone ["Wilma"]} {:rubble ["Bam-Bam"], :flintstone ["Pebbles"]}) ;; {:flintstone ("Fred" "Wilma" "Pebbles"), :rubble ("Barney" "Betty" "Bam-Bam")} (doc concat) (require 'clojure.set) (def languages #{ "java" "c" "d" "clojure"}) (def letters #{ "a" "b" "c" "d" "e"}) (def beverages #{ "java" "chai" "pop"}) (def inventors { "java" "gosling" "clojure" "hickey" "ruby" "matz"}) ;; (clojure.set/union) ;; (clojure.set/intersection) ;; (clojure.set/difference) ;; (clojure.set/select) (clojure.set/union languages beverages) ;; #{"java" "c" "d" "clojure" "chai" "pop"} (clojure.set/difference languages beverages) ;; #{"c" "d" "clojure"} (clojure.set/intersection languages beverages) ;; #{"java"} (select #(= 1 (.length %)) languages) ;; #{"c" "d"} examples.sequences/compositions ;; #{{:composer "Guiseppe Verdi", :name "Requiem"} {:composer "J. S. Bach", :name "The Art of the Fugue"} {:composer "J. S. Bach", :name "Musical Offering"} {:composer "W. A. Mozart", :name "Requiem"}} (clojure.set/rename examples.sequences/compositions {:name :title}) ;; #{{:composer "J. S. Bach", :title "Musical Offering"} {:composer "W. A. Mozart", :title "Requiem"} {:composer "Guiseppe Verdi", :title "Requiem"} {:composer "J. S. Bach", :title "The Art of the Fugue"}} ;; select is like a sql where clause (select #(= (:name %) "Requiem") examples.sequences/compositions) ;; #{{:composer "Guiseppe Verdi", :name "Requiem"} {:composer "W. A. Mozart", :name "Requiem"}} ;; project is like the list of columns in a sql select (or a view) (clojure.set/project examples.sequences/compositions [:name]) ;; #{{:name "The Art of the Fugue"} {:name "Requiem"} {:name "Musical Offering"}} ;; cross product (or join) (for [m examples.sequences/compositions c examples.sequences/countries] (concat m c)) ;; (([:composer "Guiseppe Verdi"] [:name "Requiem"] [:composer "W. A. Mozart"] [:country "Austria"]) ([:composer "Guiseppe Verdi"] [:name "Requiem"] [:composer "J. S. Bach"] [:country "Germany"]) ([:composer "Guiseppe Verdi"] [:name "Requiem"] [:composer "Guiseppe Verdi"] [:country "Italy"]) ([:composer "J. S. Bach"] [:name "The Art of the Fugue"] [:composer "W. A. Mozart"] [:country "Austria"]) ([:composer "J. S. Bach"] [:name "The Art of the Fugue"] [:composer "J. S. Bach"] [:country "Germany"]) ([:composer "J. S. Bach"] [:name "The Art of the Fugue"] [:composer "Guiseppe Verdi"] [:country "Italy"]) ([:composer "J. S. Bach"] [:name "Musical Offering"] [:composer "W. A. Mozart"] [:country "Austria"]) ([:composer "J. S. Bach"] [:name "Musical Offering"] [:composer "J. S. Bach"] [:country "Germany"]) ([:composer "J. S. Bach"] [:name "Musical Offering"] [:composer "Guiseppe Verdi"] [:country "Italy"]) ([:composer "W. A. Mozart"] [:name "Requiem"] [:composer "W. A. Mozart"] [:country "Austria"]) ([:composer "W. A. Mozart"] [:name "Requiem"] [:composer "J. S. Bach"] [:country "Germany"]) ([:composer "W. A. Mozart"] [:name "Requiem"] [:composer "Guiseppe Verdi"] [:country "Italy"])) (clojure.set/join examples.sequences/compositions examples.sequences/countries) ;; #{{:composer "J. S. Bach", :country "Germany", :name "Musical Offering"} {:composer "Guiseppe Verdi", :country "Italy", :name "Requiem"} {:composer "W. A. Mozart", :country "Austria", :name "Requiem"} {:composer "J. S. Bach", :country "Germany", :name "The Art of the Fugue"}} ;; book v2.0 page 113 4.6 Adding Properties to Lancet Tasks ;; book v3.0 page 124 6.0 Concurrency (def current-track (ref "Mars, the Bringer of War")) (deref current-track) ;; "Mars, the Bringer of War" @current-track ;; "Mars, the Bringer of War" (ref-set current-track "Venus, the Bringer of Peace") ;; *exception* (dosync (ref-set current-track "Venus, the Bringer of Peace")) ;; "Venus, the Bringer of Peace" @current-track ;; "Venus, the Bringer of Peace" ;; ACID => Atomic, Consistient, Isolated, Durable (defstruct message :sender :text) (struct message "stu" "test message") ;; {:sender "stu", :text "test message"} (def messages (ref ())) ;; works, but is inefficient... (defn naive-add-message [msg] (dosync (ref-set messages (cons msg @messages)))) ;; b/c some callers will be forced to re-try, which may be costly ;; (usually) (defn add-message [msg] (dosync (commute messages conj msg))) (add-message (struct message "user 1" "hello")) (add-message (struct message "user 2" "howdy")) (def counter (ref 0)) (defn next-counter [] (dosync (alter counter inc))) (map (fn [x] (next-counter)) (range 1 11)) ;; (22 23 24 25 26 27 28 29 30 31) ;; (32 33 34 35 36 37 38 39 40 41) ;; (doc constantly) (defn validate-message-list [lst] (if (not-every? #(and (:sender %) (:text %)) lst) (throw (IllegalStateException. "Not a valid message")))) (def messages (ref () validate-message-list)) (add-message "not a valid message") ;; when I paste the following line into the repl: ;; (.. *e getCause getCause) ;; I do see: ;; # (def counter (agent 0)) (send counter inc) @counter (await-for 1000 counter) (use '[clojure.contrib.except :only (throw-if)]) (def counter (agent 0 #(throw-if (not (number? %)) "not a number"))) (send counter inc) @counter (send counter (fn [_] "boo")) ;; # @counter ;; java.lang.Exception: Agent has errors (NO_SOURCE_FILE:0)java.lang.Exception: Agent has errors (NO_SOURCE_FILE:0) (agent-errors counter) ;; (#) (clear-agent-errors counter) (send counter inc) ;; # @counter ;; 3 (use 'examples.pi) (run-simulation 10) ;; Running on # ;; {:in-circle 10, :total 10} (guess-pi (run-simulation 100)) ;; Running on # ;; 3.08 (guess-pi (run-simulation {:in-circle 10 :total 10} 1000)) ;; Running on # ;; 3.108910891089109 (guess-pi (run-simulation 1100)) (def pi-agent (agent 100000)) (send pi-agent run-simulation) @pi-agent ;; {:in-circle 78492, :total 100000} (guess-pi @pi-agent) ;; 3.13968 (send pi-agent run-simulation 100000) ;; becomes something like: (run-simulation current-imtermediate-state 100000) (guess-pi @pi-agent) ;; 3.13788 (send pi-agent run-simulation 100000) (await-for 1000 pi-agent) (guess-pi @pi-agent) ;; 3.13788 ;; this is already defined in examples.pi, which we used above... ;; (defn parallel-guess-pi [agent-count trials] ;; (let [trials (quot trials agent-count) ;; agents (for [_ (range agent-count)] ;; (agent trials))] ;; (doseq [a agents] ;; (send a run-simulation)) ;; (apply await agents) ;; (guess-pi (apply merge-with + (map deref agents))))) (parallel-guess-pi 10 100000) ;; 3.14196 ;; book v3.0 page 134 Including Agents in Transactions (def backup-agent (agent "messages-backup.clj")) (use '[clojure.contrib.duck-streams :only (spit)]) (defn add-message-with-backup [msg] (dosync (let [snapshot (commute messages conj msg)] (send-off backup-agent (fn [filename] (spit filename snapshot) filename)) snapshot))) (add-message-with-backup (struct message "john" "message one")) (add-message-with-backup (struct message "jane" "message two")) (send backup-agent (fn [filename] (prn (slurp filename)) filename)) (agent-errors backup-agent) (clear-agent-errors backup-agent) (send backup-agent (fn [filename] (prn "slurp: " filename) (prn (slurp filename)) filename)) (slurp @backup-agent) ;; (krbutil/doc-class java.io.File) (.getCanonicalPath (java.io.File. @backup-agent)) ;; "({:sender \"jane\", :text \"message two\"} {:sender \"john\", :text \"message one\"} {:sender \"john\", :text \"message one\"} {:sender \"jane\", :text \"message two\"} {:sender \"john\", :text \"message one\"})" ;; book v3.0 page 136 6.3 Managing Per-Thread State with Va (def foo 10) foo ;; NB: in clojure/slime the output of this can be seen in the ;; *inferior-lisp* buffer... (.start (Thread. (fn [] (println foo)))) ;; (def tmp (agent 0)) ;; (let [fun (fn [state] (println "agent: foo=" foo) ;; state)] ;; (send tmp fun)) (defn print-foo [] (println foo)) (print-foo) ;; 10 (let [foo "let foo"] (print-foo)) ;; => 10 (binding [foo "bound foo"] (print-foo)) ;; bound foo (krbutil/doc-class Thread) (def tmp (agent nil)) (defn my-thread-id [state] (let [thid (.getId (Thread/currentThread)) msg (printf "Thread.getId: %s" thid)] (println msg) (list msg thid))) (my-thread-id nil) ;; Thread.getId: 499nil ;; (nil 499) (send tmp my-thread-id) @tmp ;; (nil 24) (.start (Thread. (fn [] (println @tmp)))) (agent-errors tmp) (clear-agent-errors tmp) (defn slow-double [n] (Thread/sleep 1000) (* n 2)) (slow-double 10) (defn calls-slow-double [] (map slow-double [1 2 1 2 1 2])) (time (dorun (calls-slow-double))) ;; "Elapsed time: 6000.323286 msecs" (use '[clojure.contrib.memoize :only (memoize)]) (defn demo-memoize [] (time (dorun (binding [slow-double (memoize slow-double)] (calls-slow-double))))) (demo-memoize) ;; "Elapsed time: 2001.674923 msecs" ;; book v3.0 page 138 : Working with Java Callback APIs (defn create-runonce [function agt] (let [sentinel @agt] (fn [& args] (send-off agt #(if (= % sentinel) (apply function args) %)) (await agt) @agt))) (def println-once-agent (agent :not-run-yet)) (def println-once (create-runonce println println-once-agent)) @println-once-agent ;; :not-run-yet (println-once "There can be only one!") ;; prints in the *inferior-lisp* buffer (println-once "There can be only one!") ;; *prints _nothing_* (dorun (map println-once [1 2 3 4 5])) ;; prints only the '1' in the *inferior-lisp* (println "here") (println "still here") (defn create-runonce-with-peek [function agt] (let [sentinel @agt] (fn [& args] (when (= @agt sentinel) (send-off agt #(if (= % sentinel) (apply function args) %)) (await agt)) @agt))) (defn create-has-run-predicate [agt sentinel] (fn [] (not= @agt sentinel))) (def println-once-has-run? (create-has-run-predicate println-once-agent :not-run-yet)) (println-once-has-run?) (defn reset-runonce [agt sentinel] (send agt (fn [_] sentinel)) (await agt)) (reset-runonce println-once-agent :not-run-yet) (println-once-has-run?) ;; again, this prints on the *inferior-lisp* buffer, how can I get ;; that *out* to be this *out*? send *out* as an arg maybe? (println-once "jack's back") (def tmp (agent *out*)) (defn print-at [state port & stuff] (println "port=" port ", stuff=" stuff) (binding [*out* state] (apply println stuff) state)) (send tmp print-at *out* "where does this come out?") (agent-errors tmp) (clear-agent-errors tmp) (defn runonce [function] (let [sentinel (Object.) agt (agent sentinel) reset-fn (fn [_] (send agt #(sentinel)) (await agt)) has-run? #(not= @agt sentinel)] [has-run? reset-fn (fn [& args] (when (= @agt sentinel) (send-off agt #(if (= % send-off) (apply function args) %)) (await agt)) @agt)])) ;; (ns lancet.step_3_complete) ;; (defn runonce ;; "Create a function that will only run once. All other invocations ;; return the first calculated value. The function can have side effects. ;; Returns a [has-run-predicate, reset-fn, once-fn]" ;; [function] ;; (let [sentinel (Object.) ;; agt (agent sentinel) ;; reset-fn (fn [_] (send agt #(sentinel)) (await agt)) ;; has-run? #(not= @agt sentinel)] ;; [has-run? ;; reset-fn ;; (fn [& args] ;; (when (= @agt sentinel) ;; (send-off agt ;; #(if (= % sentinel) ;; (apply function args) ;; %)) ;; (await agt)) ;; @agt)])) ;; book v3.0 page 147 : Chapter 8 Multimethods (defn my-print [ob] (.write *out* ob)) (defn my-println [ob] (my-print ob) (.write *out* "\n")) (my-println "Hello") ;;Hello (my-println nil) ;; **boom** (defn my-print [ob] (cond (nil? ob) (.write *out* "nil") (string? ob) (.write *out* ob))) (my-println nil) ;; nil (my-println [1 2 3]) ;; <> (use '[clojure.contrib.str-utils :only (str-join)]) (defn my-print-vector [ob] (.write *out* "[") (.write *out* (str-join " " ob)) (.write *out* "]")) (defn my-println [ob] (cond (vector? ob) (my-print-vector ob) (nil? ob) (.write *out* "nil") (string? ob) (.write *out* ob))) (my-println [1 2 3]) ;; [1 2 3] (defmulti my-print class) (my-print "foo") (defmethod my-print String [s] (.write *out* s)) (my-print "foo") (defmethod my-print nil [s] (.write *out* "nil")) (my-print nil) (defmethod my-print Number [n] (.write *out* (.toString n))) (my-print 42) (defmethod my-print :default [s] (.write *out* "#<") (.write *out* (.toString s)) (.write *out* "#>")) (my-print (java.sql.Date. 0)) ;; #<1969-12-31#> (my-print (java.util.Random.)) ;; #nil (defmulti my-print class :everything-else) (defmethod my-print String [s] (.write *out* s)) (defmethod my-print :everything-else [_] (.write *out* "...not implemented yet...")) ;; book v3.0 page 153 : Moving Beyond Simple Dispatch (use '[clojure.contrib.str-utils :only (str-join)]) (defmethod my-print java.util.Collection [c] (.write *out* "(") (.write *out* (str-join " " c)) (.write *out* ")")) (my-print (take 6 (cycle [1 2 3]))) ;; (1 2 3 1 2 3) (my-print [1 2 3]) ;; (1 2 3) (defmethod my-print clojure.lang.IPersistentVector [v] (.write *out* "[") (.write *out* (str-join " " v)) (.write *out* "]")) (my-println [1 2 3]) ;; that was supposed to fail, but it worked (prefer-method my-print clojure.lang.IPersistentVector java.util.Collection) (my-print (take 6 (cycle [1 2 3]))) ;; (1 2 3 1 2 3) (my-println [1 2 3]) ;; [1 2 3] (ns examples.multimethods.account) (defstruct account :id :tag :balance) :Checking ;; :Checking ::Checking ;; :examples.multimethods.account/Checking (struct account 1 ::examples.multimethods.account/Savings 100M) ;; {:id 1, :tag :examples.multimethods.account/Savings, :balance 100M} (alias 'acc 'examples.multimethods.account) (def test-savings (struct account 1 ::acc/Savings 100M)) (def test-checking (struct account 1 ::acc/Checking 250M)) (class 100M) ;; java.math.BigDecimal (defmulti interest-rate :tag) (defmethod interest-rate ::Checking [_] 0M) (defmethod interest-rate ::Savings [_] 0.05M) (interest-rate test-savings) ;; 0.05M (interest-rate test-checking) ;; 0M (defmulti account-level :tag) (defmethod account-level ::Checking [acct] (if (>= (:balance acct) 5000) ::Premium ::Basic)) (defmethod account-level ::Savings [acct] (if (>= (:balance acct) 1000) ::Premium ::Basic)) (account-level (struct account 1 ::acc/Savings 2000M)) ;; :examples.multimethods.account/Premium (account-level (struct account 1 ::acc/Checking 2000M)) ;; :examples.multimethods.account/Basic (defmulti service-charge (fn [acct] ;; (println "in selector, acct=" acct) (let [res [(account-level acct) (:tag acct)]] ;; (println "in selector, acct=" acct " => " res) res))) ;; NB: leaving out the single-arg in the defmethod service-charge: ;; (defmethod service-charge [::Basic ::Checking] [] 25) ;; results in the following, non-intuitive exception: ;; java.lang.IllegalArgumentException: Wrong number of args passed to: account$fn (NO_SOURCE_FILE:0) ;; [Thrown class clojure.lang.Compiler$CompilerException] (defmethod service-charge [::Basic ::Checking] [_] 25) (defmethod service-charge [::Basic ::Savings] [_] 10) (defmethod service-charge [::Premium ::Checking] [_] 0) (defmethod service-charge [::Premium ::Savings] [_] 0) (service-charge {:tag ::acc/Checking :balance 1000}) ;; 25 (service-charge {:tag ::acc/Savings :balance 1000}) ;; 0 (derive ::Savings ::Account) (derive ::Checking ::Account) (isa? ::acc/Savings ::acc/Account) ;; true (defmulti service-charge (fn [acct] [(account-level acct) (:tag acct)])) (defmethod service-charge [::Basic ::Checking] [_] 25) (defmethod service-charge [::Basic ::Savings] [_] 10) (defmethod service-charge [::Premium ::Account] [_] 0) (service-charge {:tag ::acc/Checking :balance 1000}) ;; 25 (service-charge {:tag ::acc/Savings :balance 1000}) ;; 0 (ns user) (use '[clojure.inspector :only (inspect inspect-tree)]) (inspect-tree (System/getProperties)) (inspect (System/getProperties)) (inspect conj) (inspect [1 2 3 4]) (inspect-tree [1 2 3 [4 5]]) (inspect-tree {:clojure {:creator "Rich" :runs-on-jvm true}}) (use :reload '[clojure.contrib.test-is :only (is)]) (is (string? 10)) ;; java.lang.AssertionError: (string? 10) was false/nil (NO_SOURCE_FILE:0) (is (instance? java.util.Collection "foo")) ;; java.lang.AssertionError: "foo" has class java.lang.String but should have java.util.Collection (NO_SOURCE_FILE:0) (is (= "power" "wisdom")) ;; java.lang.AssertionError: "power" is "power" but should be "wisdom" (NO_SOURCE_FILE:0) ;; 'is is a defmulti, internally it uses assert-expr, which has the following dispatcher: ;; (defmulti assert-expr (fn [form message] ;; (first form))) (defn map-tree [fun tree] ;; (println "map-tree: fun=" fun "; tree=" tree) (cond (nil? tree) tree (isa? tree java.util.Collection) (map (partial map-tree fun) tree) ;; atom true (fun tree))) ;; (map-tree (partial + 2) ;; '(1 2 (3 4 (5)))) ;; Ok, I was thinking there would be a way to get multi-methods to do ;; a bit of fixed destructuring...but I haven't got it figured out ;; yet... ;; (defmulti my-test (fn [& things] ;; (println "things=" things) ;; (let [res (map-tree class things)] ;; (println "things=" things "; res=" res) ;; res))) ;; (defmethod my-test [Number Number Number] ;; [a b c] ;; (+ a b c)) ;; (defmethod my-test [String String String] ;; [a b c] ;; (str a b c)) ;; (my-test 1 2 3) ;; (isa? (seq [1 2 3]) java.util.Collection) ;; (isa? java.util.Collection (seq [1 2 3])) ;; (parents (class (seq [1 2 3]))) ;; ;; #{clojure.lang.IReduce clojure.lang.IndexedSeq clojure.lang.ASeq} ;; (map parents (parents (class (seq [1 2 3])))) ;; ;; (nil #{clojure.lang.ISeq} #{clojure.lang.Obj java.util.Collection clojure.lang.ISeq}) ;; book v3.0 : Adding Type Coercions to Lancet