Download - Refactoring to Macros with Clojure

Transcript
Page 1: Refactoring to Macros with Clojure

Refactoring to Macroswith Clojure

Dimitry Solovyov@dimituri

Page 2: Refactoring to Macros with Clojure

Let's talk aboutFUNCTIONAL PROGRAMMING

Page 3: Refactoring to Macros with Clojure
Page 4: Refactoring to Macros with Clojure

liftIO  $  atomicModifyIORef  sc  $  \n  -­‐>  (n  +  1,  ())

d  <-­‐  f  v  >>:  onInner

liftIO  $  ds  `addDisposable`  d

Page 5: Refactoring to Macros with Clojure
Page 6: Refactoring to Macros with Clojure
Page 7: Refactoring to Macros with Clojure
Page 8: Refactoring to Macros with Clojure

>>:

Page 9: Refactoring to Macros with Clojure

Let's talk about

LISP

Page 10: Refactoring to Macros with Clojure

LISP in 3 minutesvia @bodiltv

Page 11: Refactoring to Macros with Clojure

object.method(a, b);

Page 12: Refactoring to Macros with Clojure

object.method( a b)

Page 13: Refactoring to Macros with Clojure
Page 14: Refactoring to Macros with Clojure

Clojure

It's a LispCompiledDynamic typesType hintsMacros

Page 15: Refactoring to Macros with Clojure

Clojure

It's a LispCompiledDynamic typesType hintsMacrosOptional static typesOptional Prolog

Page 17: Refactoring to Macros with Clojure

HttpServer  server  =  HttpServer.create(address,  0);server.createContext(path,  handler);server.setExecutor(null);server.start();

Page 18: Refactoring to Macros with Clojure

HttpServer  server  =  HttpServer.create(address,  0);server.createContext(path,  handler);server.setExecutor(null);server.start();

(doto  (HttpServer/create  address  0)    (.createContext  path  handler)    (.setExecutor  nil)    (.start))

Page 19: Refactoring to Macros with Clojure

macro |ˈmakrəәʊ|noun ( pl. macros )

1 (also macro instruction) Computing a single instruction that expands automatically into a set of instructions to perform a particular task.

Page 20: Refactoring to Macros with Clojure

(let*  [G__360  (HttpServer/create  address  0)]    (.createContext  G__360  path  handler)    (.setExecutor  G__360  nil)    (.start  G__360)    G__360)

(doto  (HttpServer/create  address  0)    (.createContext  path  handler)    (.setExecutor  nil)    (.start))

Page 21: Refactoring to Macros with Clojure

根性

Page 22: Refactoring to Macros with Clojure

System.out.println(Encoding.encodeBase64(Encoding.decodeUrl(Encoding.decodeBase64(b))));

Page 23: Refactoring to Macros with Clojure

String  url  =  Encoding.decodeBase64(b);String  decodedUrl  =  Encoding.decodeUrl(url);String  encodedUrl  =  Encoding.encodeBase64(decodedUrl);System.out.println(encodedUrl);

Page 24: Refactoring to Macros with Clojure

String  url  =  Encoding.decodeBase64(b);String  decodedUrl  =  Encoding.decodeUrl(url);String  encodedUrl  =  Encoding.encodeBase64(decodedUrl);System.out.println(encodedUrl);

(-­‐>  b    Encoding/decodeBase64    Encoding/decodeUrl    Encoding/encodeBase64    println)

Page 25: Refactoring to Macros with Clojure

-­‐>

(-­‐>  stuff    (foo  ,,,  a)    (bar  ,,,  b  c  d)    (baz  ,,,  e  f))

Page 26: Refactoring to Macros with Clojure

-­‐>>-­‐>

(-­‐>  stuff    (foo  ,,,  a)    (bar  ,,,  b  c  d)    (baz  ,,,  e  f))

(-­‐>>  stuff    (foo  a  ,,,)    (bar  b  c  d  ,,,)    (baz  e  f  ,,,))

Page 27: Refactoring to Macros with Clojure

-­‐<>-­‐>>-­‐>

(-­‐>  stuff    (foo  ,,,  a)    (bar  ,,,  b  c  d)    (baz  ,,,  e  f))

(-­‐>>  stuff    (foo  a  ,,,)    (bar  b  c  d  ,,,)    (baz  e  f  ,,,))

(-­‐<>  stuff    (foo  a  <>)    (bar  b  c  <>  d)    (baz  <>  e  f))

Page 28: Refactoring to Macros with Clojure

“Swiss Arrows”

-­‐<>> -­‐?<> -­‐!> -­‐!>>

-­‐!<> <<-­‐ -­‐< -­‐<:p

-­‐<< -­‐<<:p -­‐<>< -­‐<><:p

https://github.com/rplevy/swiss-arrows

Page 29: Refactoring to Macros with Clojure

-­‐<<:p

Page 30: Refactoring to Macros with Clojure

-­‐<<:p

Page 31: Refactoring to Macros with Clojure

Q: How do I get the result from a chain of computatoins that may fail?

Page 32: Refactoring to Macros with Clojure

PhoneNumber  number  =  phoneMap.get(person);if  (number  !=  null)  {        Carrier  carrier  =  carrierMap.get(number);        if  (carrier  !=  null)  {                return  addressMap.get(address);        }}return  null;

Page 33: Refactoring to Macros with Clojure

WHAT YOU'RE LOOKING FORIS AN OPTION MONAD

Page 34: Refactoring to Macros with Clojure
Page 35: Refactoring to Macros with Clojure

PhoneNumber  number  =  phoneMap.get(person);if  (number  !=  null)  {        Carrier  carrier  =  carrierMap.get(number);        if  (carrier  !=  null)  {                return  addressMap.get(address);        }}return  null;

(some-­‐>>    (.get  phoneMap  person)    (.get  carrierMap)    (.get  addressMap))

Page 36: Refactoring to Macros with Clojure

Clojure vectors implement

java.lang.Comparablejava.util.RandomAccess

Page 37: Refactoring to Macros with Clojure

All Clojure functions implement

java.util.Comparatorjava.lang.Runnablejava.util.concurrent.Callable

Page 38: Refactoring to Macros with Clojure

List<Integer>  numbers  =  Arrays.asList(1,  3,  4,  8,  2);Collections.sort(numbers,  new  Comparator<Integer>()  {        @Override        public  int  compare(Integer  o1,  Integer  o2)  {                return  o2.compareTo(o1);        }});

Page 39: Refactoring to Macros with Clojure

List<Integer>  numbers  =  Arrays.asList(1,  3,  4,  8,  2);Collections.sort(numbers,  new  Comparator<Integer>()  {        @Override        public  int  compare(Integer  o1,  Integer  o2)  {                return  o2.compareTo(o1);        }});

List<Integer>  numbers  =  Arrays.asList(1,  3,  4,  8,  2);Collections.sort(numbers,  (o1,  o2)  -­‐>  o2.compareTo(o1));

Page 40: Refactoring to Macros with Clojure

List<Integer>  numbers  =  Arrays.asList(1,  3,  4,  8,  2);Collections.sort(numbers,  new  Comparator<Integer>()  {        @Override        public  int  compare(Integer  o1,  Integer  o2)  {                return  o2.compareTo(o1);        }});

(doto  (ArrayList.  [1  3  4  8  2])    (Collections/sort  (fn  [o1  o2]  (.compareTo  o2  o1))))

List<Integer>  numbers  =  Arrays.asList(1,  3,  4,  8,  2);Collections.sort(numbers,  (o1,  o2)  -­‐>  o2.compareTo(o1));

Page 41: Refactoring to Macros with Clojure

List<Integer>  numbers  =  Arrays.asList(1,  3,  4,  8,  2);Collections.sort(numbers,  new  Comparator<Integer>()  {        @Override        public  int  compare(Integer  o1,  Integer  o2)  {                return  o2.compareTo(o1);        }});

(doto  (ArrayList.  [1  3  4  8  2])    (Collections/sort  (fn  [o1  o2]  (.compareTo  o2  o1))))

(sort  #(compare  %2  %1)  [1  3  4  8  2])

List<Integer>  numbers  =  Arrays.asList(1,  3,  4,  8,  2);Collections.sort(numbers,  (o1,  o2)  -­‐>  o2.compareTo(o1));

Page 42: Refactoring to Macros with Clojure
Page 43: Refactoring to Macros with Clojure

(defn  len-­‐reflected  [s]    (.length  s))

(defn  len-­‐hinted  ^String  [^String  s]    (.length  s))

user=>  (time  (dotimes  [i  1000000]  (len-­‐reflected  (str  i))))"Elapsed  time:  3204.913  msecs"niluser=>  (time  (dotimes  [i  1000000]  (len-­‐hinted  (str  i))))"Elapsed  time:  113.317  msecs"nil

Page 44: Refactoring to Macros with Clojure

Polyglot projectswith Leiningen

(defproject  clojure-­‐java  "1.0.0-­‐SNAPSHOT"    :description  "Example  Clojure+Java  project."    :min-­‐lein-­‐version  "2.0.0"    :source-­‐paths  ["src/clojure"]    :java-­‐source-­‐paths  ["src/java"]    :javac-­‐options  ["-­‐target"  "1.5"  "-­‐source"  "1.5"])

http://leiningen.org

Page 45: Refactoring to Macros with Clojure

http://www.ldn.lv

Workshop: ClojureSaturday, May 18, 201310:00 am

Citadeles iela 12, Riga

http://riga.techhub.com/

Page 46: Refactoring to Macros with Clojure

(kthx-­‐bye))))))

Page 47: Refactoring to Macros with Clojure

(defmacro  doto    [x  &  forms]    (let  [gx  (gensym)]        `(let  [~gx  ~x]              ~@(map  (fn  [f]                                (if  (seq?  f)                                    `(~(first  f)  ~gx  ~@(next  f))                                    `(~f  ~gx)))                            forms)              ~gx)))

Page 48: Refactoring to Macros with Clojure

(ns  foo.core    (:gen-­‐class))  (defn  -­‐main    "I  don't  do  a  whole  lot  ...  yet."    [&  args]    (println  "I'm  a  little  pony"))

foo$  lein  runI'm  a  little  pony

Page 49: Refactoring to Macros with Clojure

(defn  make-­‐example  []    (proxy  [Object]  []        (toString  []  "I'm  a  little  pony")))

user=>  (.toString  (make-­‐some-­‐example))"I'm  a  little  pony"

Page 50: Refactoring to Macros with Clojure

class  Example  {        void  someMethod(String  x)  {                someMethod(x,  null)        }          void  someMethod(String  x,  String  y)  {                doSomethingWith(x,  y);        }}

(proxy  [Example]  []    (toString        ([x]      (proxy-­‐super  someMethod  x))        ([x  y]  (do-­‐other-­‐stuff  this  x  y))))

Page 51: Refactoring to Macros with Clojure

(let  [^LoadingCache  cache  (doto  CacheBuilder/newBuilder                            (.maximumSize  1000)                            (.build  (reify  CacheLoader                                                (load  ^Graph  [^Key  key]  (create-­‐expensive-­‐graph  key)))))])

LoadingCache<Key,  Graph>  cache  =  CacheBuilder.newBuilder()                .maximumSize(1000)                .build(new  CacheLoader<Key,  Graph>()  {                              public  Graph  load(Key  key)  {                                      return  createExpensiveGraph(key);                              }                      });

LoadingCache<Key,  Graph>  cache  =  CacheBuilder.newBuilder()                .maximumSize(1000)                .build((key)  -­‐>  createExpensiveGraph(key));