>
Mark Bastian
3/24/2015
package interop;
import clojure.lang.RT;
import java.util.List;
import java.util.Map;
import java.util.RandomAccess;
import java.util.Set;
public class Interop {
public static void main(String[] args){
Map<String, Integer> m = (Map<String, Integer>)RT.readString("{ \"abc\" 123 }");
System.out.println(m.get("abc"));
Set<String> s = (Set<String>)RT.readString("#{ \"abc\" \"123\" }");
System.out.println(s.contains("abc"));
List<String> v = (List<String>)RT.readString("[ \"abc\" ]");
System.out.println(v.get(0));
System.out.println(v instanceof RandomAccess);
}
}
Note: Read Only
Java
final Set<String> names = new HashSet<String>();
final List<Integer> ages = new LinkedList<Integer>();
final Map<String, Integer> names2ages = new HashMap<String, Integer>();
Clojure
(def names #{})
(def ages [])
(def names->ages {})
final Set<String> names = new HashSet<String>();
names.add("Curly");
names.add("Larry");
names.add("Moe");
final List<Integer> ages = new LinkedList<Integer>();
ages.add(20);
ages.add(21);
ages.add(22);
final Map<String, Integer> names2ages = new HashMap<String, Integer>();
//This is inefficient but preserves our list
int i = 0;
for(String name : names){
names2ages.put(name, ages.get(i));
i++;
}
//This is efficient since we are popping, but the list is mutated :(
for(String name : names){
names2ages.put(name, ages.remove(0));
}
Clojure
(def names #{ "Curly" "Larry" "Moe"})
(def ages [20 21 22])
(def names->ages (zipmap names ages))
Clojure
(conj [1 2 3] 4) ;Vector insertion
=> [1 2 3 4] ;Faster to add at the end
(conj #{1 2 3} 4) ;Set insertion
=> #{1 4 3 2}
(conj {"ONE" 1 "TWO" 2 "THREE" 3} ["FOUR" 4]) ;Map insertion
=> {"FOUR" 4, "THREE" 3, "TWO" 2, "ONE" 1}
(conj '(1 2 3) 4) ;List insertion
=> (4 1 2 3) ;Faster to add at the front
One function for "efficient" collection addition
Clojure
(get [1 2 3 4] 2) ;Get the item at index 2
=> 3
(get #{1 2 3 4} 2) ;Get 2 from the set
=> 2
(get {"ONE" 1 "TWO" 2 "THREE" 3 "FOUR" 4} "TWO") ;Get "TWO" from the map
=> 2
Same interface for any random access data structure
Clojure
(get [1 2 3 4] 5)
=> nil
(get #{1 2 3 4} 5)
=> nil
(get {"ONE" 1 "TWO" 2 "THREE" 3 "FOUR" 4} "FIVE")
=> nil
Clojure
(get [1 2 3 4] 5 5)
=> 5
(get #{1 2 3 4} 5 5)
=> 5
(get {"ONE" 1 "TWO" 2 "THREE" 3 "FOUR" 4} "FIVE" 5)
=> 5
Get takes an optional final argument to return when the item is missing from the collection
Clojure
;Nested & Heterogeneous
(def data { :a 1 :b [1 2 3 4 5] :c { :name "Bob" :age 19 }})
=> #'user/data
(get-in data [:c :name]) ;I can drill down
=> "Bob"
(get-in data [:foo :baz :wonk]) ;Bad paths just return nil
=> nil
(get-in data [:c "shoe size"] 14) ;I can provide defaults
=> 14
Clojure
;Nested & Heterogeneous
(def data { :a 1 :b [1 2 3 4 5] :c { :name "Bob" :age 19 }})
=> #'user/data
(update-in data [:c :age] inc) ;Update value via a function
=> {:c {:age 20, :name "Bob"}, :b [1 2 3 4 5], :a 1}
(assoc-in data [:c "shoe size"] 14) ;insert or replace
=> {:c {:age 19, :name "Bob", "shoe size" 14}, :b [1 2 3 4 5], :a 1}
Clojure
(require 'clojure.edn)
=> nil
(def data { :a 1 :b [1 2 3 4 5] :c { :name "Bob" :age 19 }})
=> #'user/data
(spit "my.edn" data)
=> nil
(def reconstituted (clojure.edn/read-string (slurp "my.edn")))
=> #'user/reconstituted
reconstituted
=> {:c {:age 19, :name "Bob"}, :b [1 2 3 4 5], :a 1}
(def code-or-data? { :name "Bob" :age 40 :shoe-size 10 })
=> #'user/code-or-data?
(prn code-or-data?)
{:age 40, :shoe-size 10, :name "Bob"}
=> nil
(+ 2 3 4 5 6)
=> 20
'(+ 2 3 4 5 6)
=> (+ 2 3 4 5 6)
(defmacro ? "Print a form and its value"
[& rest]
`(doto ~rest (->> (str '~rest " -> ") prn)))
=> #'user/?
;This form is pretty simple, but what if you wanted to know what it did?
(+ 1 2 3 4 5 6 7)
=> 28
;You could do this, but it is ugly and you have to pull out the form later.
(prn (+ 1 2 3 4 5 6 7))
28
=> nil
;Just stick the macro in there and see...
(? + 1 2 3 4 5 6 7)
"(+ 1 2 3 4 5 6 7) -> 28"
=> 28
Clojure
(require '(clojure.data [json :as json]))
=> nil
(json/write-str {:a 1 :b [1 2 3 4 5]})
=> "{\"b\":[1,2,3,4,5],\"a\":1}"
(json/read-str "{\"a\":1,\"b\":[1,2,3,4]}" :key-fn keyword)
=> {:a 1, :b [1 2 3 4]}
https://github.com/clojure/data.jsonClojure
(require 'hiccup.core)
=> nil
(def slide
[:section
[:h2 "Wouldn't it be cool if..."]
[:ul
[:li "You could write code that runs on the JVM?"]
[:li "And run as JavaScript in the browser?"]
[:li "And transform itself to and from HTML?"]
[:li "And transform itself to and from JSON?"]
[:li "That would be awesome!"]]])
=> #'user/slide
(def html-text (hiccup.core/html slide))
=> #'user/html-text
html-text
=> "<section><h2>Wouldn't it be cool if...<ul><li>You could write code that runs on the JVM?</li><li>And run as JavaScript in the browser?</li><li>And transform itself to and from HTML?</li><li>And transform itself to and from JSON?</li><li>That would be awesome!</li></ul></h2></section>"
(require '[hiccup-bridge.core :as hicv])
=> nil
(def recovered (hicv/html->hiccup html-text))
=> #'user/recovered
recovered
=> ([:section [:h2 "Wouldn't it be cool if..."] [:ul [:li "You could write code that runs on the JVM?"] [:li "And run as JavaScript in the browser?"] [:li "And transform itself to and from HTML?"] [:li "And transform itself to and from JSON?"] [:li "That would be awesome!"]]])
(= slide (first recovered))
=> true
(doc and)
-------------------------
clojure.core/and
([] [x] [x & next])
Macro
Evaluates exprs one at a time, from left to right. If a form
returns logical false (nil or false), and returns that value and
doesn't evaluate any of the other expressions, otherwise it returns
the value of the last expr. (and) returns true.
=> nil
(source let)
(defmacro let
"binding => binding-form init-expr
Evaluates the exprs in a lexical context in which the symbols in
the binding-forms are bound to their respective init-exprs or parts
therein."
{:added "1.0", :special-form true, :forms '[(let [bindings*] exprs*)]}
[bindings & body]
(assert-args
(vector? bindings) "a vector for its binding"
(even? (count bindings)) "an even number of forms in binding vector")
`(let* ~(destructure bindings) ~@body))
=> nil
(find-doc "macro expansion")
-------------------------
clojure.pprint/*print-suppress-namespaces*
Don't print namespaces with symbols. This is particularly useful when
pretty printing the results of macro expansions
=> nil