Slide 1

Slide 1 text

NATE SMITH @nwjsmith

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

CLOJURE

Slide 4

Slide 4 text

LISP CONCURRENCY STATE MODEL JAVA INTEROP

Slide 5

Slide 5 text

LISP CONCURRENCY STATE MODEL JAVA INTEROP NOPE

Slide 6

Slide 6 text

Y X

Slide 7

Slide 7 text

CLOJURE RUBY

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

COLLECTION PROCESSING 1 EXPRESSION PROBLEM 2 META PROGRAMMING 3

Slide 10

Slide 10 text

A BRIEF DETOUR

Slide 11

Slide 11 text

FUNCTIONAL DYNAMIC JVM

Slide 12

Slide 12 text

FUNCTIONAL DYNAMIC JS

Slide 13

Slide 13 text

12345678987654 ; Arbitrary precision integers 1.234 ; Doubles 1.234M ; BigDecimals 22/7 ; Rational numbers "chunky bacon" ; Strings chunky bacon ; Symbols :chunky :bacon ; Keywords true false ; Boolean nil ; Null #"^chunky\s+bacon$" ; Regular expressions \A \b \u2603 ; Characters (UTF-16)

Slide 14

Slide 14 text

; Lists - singly-linked, grow at front (1 2 3 4 5) (chunky bacon) (list 1 2 3) ; Vectors - indexed, grow at end [1 2 3 4 5] [chunky bacon] ; Maps - key/value lookup {:chunky "bacon", :foo "bar"} {:one 1 :two 2} ; Sets #{:chunky :bacon}

Slide 15

Slide 15 text

(println "Hello, World!") ; Hello, World! ; => nil (println (+ 1 2 3)) ; 6 ; => nil

Slide 16

Slide 16 text

(defn hello "Print a greeting." [first-name last-name] (let [full (str first-name " " last-name)] (println full)))

Slide 17

Slide 17 text

def hello(first_name, last_name) full = "#{first_name} #{last_name}" puts full end (defn hello "Print a greeting." [first-name last-name] (let [full (str first-name " " last-name)] (println full)))

Slide 18

Slide 18 text

(those parentheses (are (weird)))

Slide 19

Slide 19 text

(defn hello "Print a greeting." [first-name last-name] (let [full (str first-name " " last-name)] (println full)))

Slide 20

Slide 20 text

(defn hello "Print a greeting." [first-name last-name] (let [full (str first-name " " last-name)] (println full)))

Slide 21

Slide 21 text

SYNTAX

Slide 22

Slide 22 text

PROCESSING COLLECTIONS

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

include Enumerable

Slide 25

Slide 25 text

#each

Slide 26

Slide 26 text

File.open("/etc/hosts").each do |line| puts line end [1, 2, 3].each { |n| puts n + 1 }

Slide 27

Slide 27 text

all? any? chunk collect collect_concat count cycle detect drop drop_while each_cons each_entry each_slice each_with_index each_with_object entries find find_all find_index first flat_map grep group_by include? inject lazy map max max_by member? min min_by minmax minmax_by none? one? partition reduce reject reverse_each select slice_before sort sort_by take take_while to_a to_set zip

Slide 28

Slide 28 text

THE RIGHT ABSTRACTION OVER COLLECTIONS

Slide 29

Slide 29 text

#each

Slide 30

Slide 30 text

all? any? chunk collect collect_concat count cycle detect drop drop_while each_cons each_entry each_slice each_with_index each_with_object entries find find_all find_index first flat_map grep group_by include? inject lazy map max max_by member? min min_by minmax minmax_by none? one? partition reduce reject reverse_each select slice_before sort sort_by take take_while to_a to_set zip

Slide 31

Slide 31 text

[1, 2, 3, 4, 5].drop(2) # => [3, 4, 5] (0..99).inject(&:+) # => 4950 [1, 2, 3, 4].map { |n| n += 1 } # => [2, 3, 4, 5] {one: 1, two: 2, three: 3}.all? { |k, v| v < 10 } # => true Set.new([3, 5, 7, 8, 9, 10]).any? { |n| n.even? } # => true

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

SEQUENCE

Slide 34

Slide 34 text

SEQUENCE

Slide 35

Slide 35 text

; if collection is not empty return ; a seq object, otherwise return nil (seq coll) ; return the first item in the ; seq, or nil if there are no items (first seq) ; return a seq representing the rest ; of the sequence (rest seq) ; return a seq where item is the ; first element and seq the rest (cons item seq)

Slide 36

Slide 36 text

apply butlast concat cons cycle distinct doall dorun doseq drop drop-last drop-while empty? every? ffirst filter first flatten fnext for frequencies group-by interleave interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all partition-by pmap rand-nth realized? reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take-nth take-while to-array-2d vec when-first zipmap

Slide 37

Slide 37 text

(drop 2 [1 2 3 4 5]) ; => (3 4 5) [1, 2, 3, 4, 5].drop(2) # => [3, 4, 5] (reduce + (range 100)) ; => 4950 (0..99).inject(&:+) # => 4950 (map inc [1 2 3 4]) ; => (2 3 4 5) [1, 2, 3, 4].map { |n| n += 1 } # => [2, 3, 4, 5] (every? (fn [[k v]] (< v 10)) {:one 1 :two 2 :three 3}) ; => true {one: 1, two: 2, three: 3}.all? { |k, v| v < 10 } # => true (some even? #{3 5 7 8 9 10}) ; => true Set.new([3, 5, 7, 8, 9, 10]).any? { |n| n.even? } # => true

Slide 38

Slide 38 text

(drop 2 [1 2 3 4 5]) ; => (3 4 5) [1, 2, 3, 4, 5].drop(2) # => [3, 4, 5] (reduce + (range 100)) ; => 4950 (0..99).inject(&:+) # => 4950 (map inc [1 2 3 4]) ; => (2 3 4 5) [1, 2, 3, 4].map { |n| n += 1 } # => [2, 3, 4, 5] (every? (fn [[k v]] (< v 10)) {:one 1 :two 2 :three 3}) ; => true {one: 1, two: 2, three: 3}.all? { |k, v| v < 10 } # => true (some even? #{3 5 7 8 9 10}) ; => true Set.new([3, 5, 7, 8, 9, 10]).any? { |n| n.even? } # => true

Slide 39

Slide 39 text

THAT’S GREAT, BUT HOW IS THIS BETTER?

Slide 40

Slide 40 text

(take 10 (cycle [1 2 3 4])) ; => (1 2 3 4 1 2 3 4 1 2)

Slide 41

Slide 41 text

; if collection is not empty return ; a seq object, otherwise return nil (seq coll) ; return the first item in the ; seq, or nil if there are no items (first seq) ; return a seq representing the rest ; of the sequence (rest seq) ; return a seq where item is the ; first element and seq the rest (cons item seq)

Slide 42

Slide 42 text

LAZY

Slide 43

Slide 43 text

first rest

Slide 44

Slide 44 text

(take 10 (cycle [1 2 3 4])) ; => (1 2 3 4 1 2 3 4 1 2) (take 10 (repeatedly (fn [] (rand-int 9)))) ; => (4 6 5 3 4 0 6 3 2) (take 10 (map inc (cycle [1 2 3 4]))) ; => (2 3 4 5 2 3 4 5 2 3)

Slide 45

Slide 45 text

THE RIGHT ABSTRACTION OVER COLLECTIONS

Slide 46

Slide 46 text

THE RIGHT ABSTRACTION OVER COLLECTIONS

Slide 47

Slide 47 text

IT IS BETTER TO HAVE 100 FUNCTIONS OPERATE ON 1 DATA STRUCTURE THAN 10 FUNCTIONS ON 10 DATA STRUCTURES

Slide 48

Slide 48 text

IT IS BETTER TO HAVE 100 FUNCTIONS OPERATE ON 1 DATA STRUCTURE THAN 10 FUNCTIONS ON 10 DATA STRUCTURES

Slide 49

Slide 49 text

IT IS BETTER TO HAVE 100 FUNCTIONS OPERATE ON 1 ABSTRACTION THAN 10 FUNCTIONS ON 10 ABSTRACTIONS

Slide 50

Slide 50 text

?

Slide 51

Slide 51 text

EXPRESSION PROBLEM

Slide 52

Slide 52 text

class Circle def initialize(radius) @radius = radius end def area Math::PI * (@radius ** 2) end end

Slide 53

Slide 53 text

(defrecord Circle [radius]) (defn area "Calculate the area of a shape." [shape] (* Math/PI (* (:radius shape) (:radius shape))))

Slide 54

Slide 54 text

class Circle def initialize(radius) @radius = radius end def area Math::PI * (@radius ** 2) end end

Slide 55

Slide 55 text

class Circle def initialize(radius) @radius = radius end def area Math::PI * (@radius ** 2) end end class Square def initialize(side) @side = side end def area @side ** 2 end end

Slide 56

Slide 56 text

(defrecord Circle [radius]) (defn area "Calculate the area of a shape." [shape] (* Math/PI (* (:radius shape) (:radius shape))))

Slide 57

Slide 57 text

(defrecord Circle [radius]) (defrecord Square [side]) (defn area "Calculate the area of a shape." [shape] (if (= Circle (class shape)) (* Math/PI (* (:radius shape) (:radius shape))) (* (:side shape) (:side shape))))

Slide 58

Slide 58 text

class Circle def initialize(radius) @radius = radius end def area Math::PI * (@radius ** 2) end end class Square def initialize(side) @side = side end def area @side ** 2 end end

Slide 59

Slide 59 text

(defrecord Circle [radius]) (defn area "Calculate the area of a shape." [shape] (* Math/PI (* (:radius shape) (:radius shape))))

Slide 60

Slide 60 text

(defrecord Circle [radius]) (defn area "Calculate the area of a shape." [shape] (* Math/PI (* (:radius shape) (:radius shape)))) (defn perimeter "Calculate the perimeter of a shape." [shape] (* Math/PI (* 2 (:radius shape))))

Slide 61

Slide 61 text

area Circle

Slide 62

Slide 62 text

area Circle Square

Slide 63

Slide 63 text

area Circle Square

Slide 64

Slide 64 text

area perimeter Circle Square

Slide 65

Slide 65 text

area perimeter Circle Square

Slide 66

Slide 66 text

area perimeter Circle Square ?

Slide 67

Slide 67 text

No content

Slide 68

Slide 68 text

MONKEY PATCHING

Slide 69

Slide 69 text

class Circle def initialize(radius) @radius = radius end def area Math::PI * (@radius ** 2) end end class Square def initialize(side) @side = side end def area @side ** 2 end end

Slide 70

Slide 70 text

class Circle def perimeter 2 * Math::PI * @radius end end class Square def perimeter @side * 4 end end

Slide 71

Slide 71 text

area perimeter Circle Square

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

PROTOCOLS

Slide 74

Slide 74 text

(defrecord Circle [radius]) (defrecord Square [side]) (defprotocol Shape "A shape." (area [shape] "Calculate the area of the shape") (perimeter [shape] "Calculate the perimeter of the shape")) (extend-type Circle Shape (area [c] (* Math/PI (* (:radius c) (:radius c)))) (perimeter [c] (* 2 Math/PI (:radius c)))) (extend-type Square Shape (area [s] (* (:side s) (:side s))) (perimeter [s] (* 4 (:side s))))

Slide 75

Slide 75 text

(defrecord Circle [radius]) (defrecord Square [side]) (defprotocol Shape "A shape." (area [shape] "Calculate the area of the shape") (perimeter [shape] "Calculate the perimeter of the shape")) (extend-type Circle Shape (area [c] (* Math/PI (* (:radius c) (:radius c)))) (perimeter [c] (* 2 Math/PI (:radius c)))) (extend-type Square Shape (area [s] (* (:side s) (:side s))) (perimeter [s] (* 4 (:side s))))

Slide 76

Slide 76 text

(defrecord Circle [radius]) (defrecord Square [side]) (defprotocol Shape "A shape." (area [shape] "Calculate the area of the shape") (perimeter [shape] "Calculate the perimeter of the shape")) (extend-type Circle Shape (area [c] (* Math/PI (* (:radius c) (:radius c)))) (perimeter [c] (* 2 Math/PI (:radius c)))) (extend-type Square Shape (area [s] (* (:side s) (:side s))) (perimeter [s] (* 4 (:side s))))

Slide 77

Slide 77 text

(defrecord Circle [radius]) (defrecord Square [side]) (defprotocol Shape "A shape." (area [shape] "Calculate the area of the shape") (perimeter [shape] "Calculate the perimeter of the shape")) (extend-type Circle Shape (area [c] (* Math/PI (* (:radius c) (:radius c)))) (perimeter [c] (* 2 Math/PI (:radius c)))) (extend-type Square Shape (area [s] (* (:side s) (:side s))) (perimeter [s] (* 4 (:side s))))

Slide 78

Slide 78 text

area perimeter Circle Square

Slide 79

Slide 79 text

THAT’S GREAT, BUT HOW IS THIS BETTER?

Slide 80

Slide 80 text

MONKEY PATCHING

Slide 81

Slide 81 text

MONKEY PATCHING AT

Slide 82

Slide 82 text

PROTOCOLS

Slide 83

Slide 83 text

NAME SPACES

Slide 84

Slide 84 text

(ns janky.json (:require [clojure.string :as string])) (defprotocol JSON (to-json [value] "Convert value to JSON string")) (extend-protocol JSON java.lang.Number (to-json [n] (str n)) java.lang.CharSequence (to-json [cs] (str \" cs \")) clojure.lang.Named (to-json [named] (str \" (name named) \")) java.util.Collection (to-json [coll] (str \[ (string/join \, (map to-json coll)) \]))) (to-json [:hello "goodbye" 1 3.21 #{1 2} 'foo]) ; => "[\"hello\",\"goodbye\",1,3.21,[1,2],\"foo\"]"

Slide 85

Slide 85 text

?

Slide 86

Slide 86 text

META PROGRAMMING

Slide 87

Slide 87 text

CODE THAT WRITES CODE

Slide 88

Slide 88 text

No content

Slide 89

Slide 89 text

class Player attr_accessor :name end player = Player.new player.name # => nil player.name = "Phil Kessel" player.name # => "Phil Kessel"

Slide 90

Slide 90 text

class Player def name @name end def name=(name) @name = name end end

Slide 91

Slide 91 text

class Player attr_accessor :name end player = Player.new player.name # => nil player.name = "Phil Kessel" player.name # => "Phil Kessel"

Slide 92

Slide 92 text

class Player attribute_accessor :name end

Slide 93

Slide 93 text

class Class def attribute_accessor(attribute) end end

Slide 94

Slide 94 text

class Class def attribute_accessor(attribute) define_method attribute.to_s do instance_variable_get("@#{attribute}") end define_method "#{attribute}=" do |value| instance_variable_set "@#{attribute}", value end end end

Slide 95

Slide 95 text

class Class def attribute_accessor(attribute) define_method attribute.to_s do instance_variable_get("@#{attribute}") end define_method "#{attribute}=" do |value| instance_variable_set "@#{attribute}", value end nil end end

Slide 96

Slide 96 text

class Player attribute_accessor :name end player = Player.new player.name # => nil player.name = "Phil Kessel" player.name # => "Phil Kessel"

Slide 97

Slide 97 text

class Player attribute_accessor :name end player = Player.new player.name # => nil player.name = "Phil Kessel" player.name # => "Phil Kessel"

Slide 98

Slide 98 text

No content

Slide 99

Slide 99 text

(defrecord Player [name]) (def player (->Player nil)) (:name player) ; => nil (assoc player :name "Phil Kessel")

Slide 100

Slide 100 text

(attribute-accessor :name) (defn get-name [record] (:name player)) (defn set-name [record value] (assoc player :name "Phil Kessel"))

Slide 101

Slide 101 text

(attribute-accessor :name) (defn get-name [record] (:name player)) (defn set-name [record value] (assoc player :name value))

Slide 102

Slide 102 text

(attribute-accessor :name) (get-name player) ; => "Phil Kessel" (set-name player "Joffrey Lupul") ; => #Player{:name "Joffrey Lupul"}

Slide 103

Slide 103 text

MACROS

Slide 104

Slide 104 text

(attribute-accessor :name) (defmacro attribute-accessor [attr-name] (let [n (name attr-name) reader (symbol (str "get-" n)) writer (symbol (str "set-" n))] `(do (defn ~reader [record#] (get record# ~attr-name)) (defn ~writer [record# value#] (assoc record# ~attr-name value#)))))

Slide 105

Slide 105 text

(attribute-accessor :name) (defmacro attribute-accessor [attr-name] (let [n (name attr-name) reader (symbol (str "get-" n)) writer (symbol (str "set-" n))] `(do (defn ~reader [record#] (get record# ~attr-name)) (defn ~writer [record# value#] (assoc record# ~attr-name value#)))))

Slide 106

Slide 106 text

(attribute-accessor :name) (defmacro attribute-accessor [attr-name] (let [n (name attr-name) reader (symbol (str "get-" n)) writer (symbol (str "set-" n))] `(do (defn ~reader [record#] (get record# ~attr-name)) (defn ~writer [record# value#] (assoc record# ~attr-name value#)))))

Slide 107

Slide 107 text

(attribute-accessor :name) (do (defn get-name [record] (get record :name)) (defn set-name [record value] (assoc record :name value)))

Slide 108

Slide 108 text

THAT’S GREAT, BUT HOW IS THIS BETTER?

Slide 109

Slide 109 text

CODE THAT WRITES CODE

Slide 110

Slide 110 text

No content

Slide 111

Slide 111 text

class Class def attribute_accessor(attribute) define_method attribute.to_s do instance_variable_get("@#{attribute}") end define_method "#{attribute}=" do |value| instance_variable_set "@#{attribute}", value end nil end end

Slide 112

Slide 112 text

No content

Slide 113

Slide 113 text

FOR REALZ

Slide 114

Slide 114 text

unless 1 > 2 "this will be returned" else "this won't" end

Slide 115

Slide 115 text

def unless(test, then_clause, else_clause) end

Slide 116

Slide 116 text

(unless (> 1 2) "this will be returned" "this won't")

Slide 117

Slide 117 text

(defmacro unless [test-exp then else] `(if (not ~test-exp) ~then ~else))

Slide 118

Slide 118 text

LISP IS A PROGRAMMABLE PROGRAMMING LANGUAGE JOHN FODERADO

Slide 119

Slide 119 text

?

Slide 120

Slide 120 text

SOME MAY SAY RUBY IS A BAD RIP-OFF OF LISP OR SMALLTALK, AND I ADMIT THAT. BUT IT IS NICER TO ORDINARY PEOPLE. MATZ

Slide 121

Slide 121 text

THANK YOU