Professional Documents
Culture Documents
Dynamic programming languages are powerful, productive Errors from dynamic typing are not fun
Dynamic programming languages are powerful, productive Errors from dynamic typing are not fun Too much type information is trapped inside
Dynamic programming languages are powerful, productive Errors from dynamic typing are not fun Too much type information is trapped inside We can do better without resorting to static types
better but...
we want to enumerate what is allowed duck-typing doesnt let us specify a specific set of things which are allowed
we want to enumerate what is allowed duck-typing doesnt let us specify a specific set of things which are allowed
Types are often too coarse a granularity for the kind of dispatch we would like to specify
we want to enumerate what is allowed duck-typing doesnt let us specify a specific set of things which are allowed
Types are often too coarse a granularity for the kind of dispatch we would like to specify Duck-typing can be a source of pain.
we want to enumerate what is allowed duck-typing doesnt let us specify a specific set of things which are allowed
Types are often too coarse a granularity for the kind of dispatch we would like to specify Duck-typing can be a source of pain. Pre and post conditions are also trapped inside functions
we often reach into a data structure to pull it part ... but isnt this just like what we do w/ cond + map? vector?
(let [[x & r] s] (cond (= x 1) ... (= x 2) ... (= (second s) :foo) ... ...))
this where we are today with match... well talk about this but note that this is very much a chocolate fudge machine infused cond
(match [x] [[1 & r]] ... [[2 & r]] ... [[_ :foo & r]] ... ...)
(extend-pred foo [[1 & r]] ...) (extend-pred foo [[2 & r]] ...) (extend-pred foo [[_ :foo & r]] ...)
Goals
10
Goals
10
Goals
As fast or faster than destructuring for matches with few cases Pattern matching should follow destructuring syntax when possible
10
Goals
As fast or faster than destructuring for matches with few cases Pattern matching should follow destructuring syntax when possible Extensible (!)
10
Goals
As fast or faster than destructuring for matches with few cases Pattern matching should follow destructuring syntax when possible Extensible (!) Testbed for predicate dispatch
10
pattern matching
11
12
Popular feature among functional programming languages - Standard ML, Erlang, Haskell, OCaml, Scala
12
Popular feature among functional programming languages - Standard ML, Erlang, Haskell, OCaml, Scala Literature on ecient pattern matching in the ML language family is extensive
12
Popular feature among functional programming languages - Standard ML, Erlang, Haskell, OCaml, Scala Literature on ecient pattern matching in the ML language family is extensive Decisions trees and backtracking automata popular approaches
12
13
13
Pattern matching in ML restricts the types in the columns We want pattern matching to work across types
13
Luc Maranget
14
15
16
16
16
Compiling Pattern Matching to Good Decision Trees Simple compilation algorithm Big idea is choosing which column to test based on the notion of necessity from lazy pattern matching
16
17
false and true are literals, _ is a wildcard pattern, it will match anything
18
x [_ [f [_ [_ [_
y f t _ _ _
z t] _] f] t] _]
1 2 3 4 5
19
top down evaluation order, we dont need to test anything below a wildcard
x [_ [f [_ [_ [_
y f t _ _ _
z t] _] f] t] _]
1 2 3 4 5
20
y [_ [f [_ [_ [_ f t _ _ _ t] _] f] t] _]
1 2 3 4 5
21
y [f [t [_ [_ [_
x _ f _ _ _
z t] _] f] t] _]
1 2 3 4 5
22
Matrix Specialization
23
#{t f}
24
we remove the rows that dont match the value for y. we drop the y column. here are the next pattern matrices for the t wo values of y
x [f [_ [_ [_ x [_ [_ [_ [_
z _] f] t] _] z t] f] t] _]
2 3 4 5
1 3 4 5
25
rinse, repeat
26
(cond (= y false) (cond (= z false) (let [] 3) (= z true) (let [] 1) :else (throw (java.lang.Exception. "Found FailNode"))) (= y true) (cond (= x false) (let [] 2) :else (cond (= z false) 3 (= z true) 4 :else (throw (java.lang.Exception. "Found FailNode")))) :else (cond (= z false) (let [] 3) (= z true) (let [] 4) :else (throw (java.lang.Exception. "Found FailNode"))))
we can take that process and produce a nested conditional. note that the order testing matches what we saw in previous slides
27
28
28
a pattern matrix is composed of pattern rows pattern rows contain all the specied patterns in addition to an action
28
a pattern matrix is composed of pattern rows pattern rows contain all the specied patterns in addition to an action pattern rows must all be of the same size (equal number of patterns)
28
29
29
Patterns in match are implemented as deftypes The key protocol for a pattern to extend is ISpecializeMatrix which denes a single protocol fn - specialize-matrix
29
Patterns in match are implemented as deftypes The key protocol for a pattern to extend is ISpecializeMatrix which denes a single protocol fn - specialize-matrix The pattern produces the new matrix after specialization. This may involve introducing new occurrences.
29
y [f [t [_ [_
x _ f _ _
z t] _] f] t]
30
31
32
when the matrix is specialized by SeqPattern we get this new pattern matrix. We have the occurrence that represents the head of the list and the tail of the list.
xh xt [1 r] [2 r] [3 r]
33
1 SwitchNodex 2 3 fail
35
36
We end up with a tree of switch nodes. Each switch nodes represents a occurrence/binding and a multiway test which points to other switch nodes, leaf nodes, or fail nodes.
36
We end up with a tree of switch nodes. Each switch nodes represents a occurrence/binding and a multiway test which points to other switch nodes, leaf nodes, or fail nodes. This is the decision tree.
36
Examples
37
Seq pattern matching note that the length of the seq patterns do no matter!
(match [x] [[1] :a0 [[1 2]] :a1 [[1 2 nil nil nil]] :a2 :else :a3)
38
note the rest pattern syntax support just like destructuring. notice that we can introduce bindings anywhere we would use a wildcard
(match [x] [[1]] :a0 [[_ 2 & [a & b]]] [:a1 a b] :else :a2)
39
(match [x] [{_ :a 2 :b}] :a0 [{1 :a _ :c}] :a1 [{3 :c _ :d 4 :e}] :a2 :else :a3)
40
we can restrict that only maps with the exact keys will match
(match [x] [{_ :a 2 :b :only [:a :b]}] :a0 [{1 :a c :c}] :a1 [{3 :c d :d 4 :e}] :a2 :else :a3)
41
or patterns!
42
Guards!
(match [y] [[_ (a :when even?) _ _]] :a0 [[_ (b :when [odd? div3?]) _ _]] :a1 :else :a2)
43
sometimes you want to match a specific portion and bind that to a local name
(match [v] [[3 1]] :a0 [[([1 a] :as b)]] [:a1 a b] :else :a2)
44
(extend-type java.util.Date IMatchLookup (val-at* [this k not-found] (case k :year (.getYear this) :month (.getMonth this) :date (.getDate this) :hours (.getHours this) :minutes (.getMinutes this) not-found)))
45
(let [d (java.util.Date. 2010 10 1 12 30)] (match [d] [{2009 :year a :month}] [:a0 a] [{(2010 | 2011) :year b :month}] [:a1 b]))
46
problems
47
problems
47
problems
Pattern matching is closed We want the matching to happen at the level of our most powerful abstraction functions
47
problems
Pattern matching is closed We want the matching to happen at the level of our most powerful abstraction functions Without open dispatch, all we have is a chocolate fudge machine powered cond
47
multimethods?
48
problems
49
problems
49
problems
Hard coded dispatch function In order to specify complex matches we have to construct a collection
49
problems
Hard coded dispatch function In order to specify complex matches we have to construct a collection For complex matches, performance is less than we would like
49
future directions
50
future directions
Vector patterns: for any data type that supports random access and fast slicing - PersistentVector, primitive arrays, buers, etc.
50
future directions
Vector patterns: for any data type that supports random access and fast slicing - PersistentVector, primitive arrays, buers, etc. Predicate Dispatch (huh?)
50
predicate dispatch
51
52
52
52
static vs. dynamic closed vs. open fast vs. slow (ouch)
52
Goals
53
Goals
53
Goals
move the matching to level of function, as with multimethods this change is in conict with the semantics of pattern matching - pattern matching is ordered
53
Goals
move the matching to level of function, as with multimethods this change is in conict with the semantics of pattern matching - pattern matching is ordered We need some way to know where to put new pattern rows in the matrix
53
A Sketch
54
A Sketch
54
A Sketch
Use core.logic to order the pattern rows A high performance in-memory DAG representation of the decision tree
54
A Sketch
Use core.logic to order the pattern rows A high performance in-memory DAG representation of the decision tree Perhaps we can go the route of deftypeinline patterns get best performance
54
Challenges
55
Challenges
55
Challenges
How much of the pattern matching syntax can we bring over? How close can we get to the performance of static code?
55
Challenges
How much of the pattern matching syntax can we bring over? How close can we get to the performance of static code? Can we limit the scope of changes to namespaces?
55
(defpred foo ([{a :a} 0] ...) ([{a :a} (y :when even?)] ...)) (extend-pred foo [{c :c} 3] ...)
56
Questions?
57