Slide 1

Slide 1 text

Check Exhaustivity of Pattern Match: A Generic Algorithm Fengyun Liu Scala Symposium 2016, Amsterdam, Netherlands EPFL, Switzerland

Slide 2

Slide 2 text

The Problem

Slide 3

Slide 3 text

Pattern Matching A slip in code: val d: Option[List[Int]] = ... d match { case Some(x::xs) => true case None => false } 2

Slide 4

Slide 4 text

Pattern Matching A slip in code: val d: Option[List[Int]] = ... d match { case Some(x::xs) => true case None => false } Warning: match may not be exhaustive. It would fail on the following input: Some(Nil) 2

Slide 5

Slide 5 text

The Problem It’s a solved problem for ADTs L. Maranget, Warnings for pattern matching, Journal of Functional Programming, 2007 3

Slide 6

Slide 6 text

The Problem It’s a solved problem for ADTs L. Maranget, Warnings for pattern matching, Journal of Functional Programming, 2007 How to handle growing complexity of type systems? • GADTs • subtyping • mixins • typecase • path-dependent types • union types • ... 3

Slide 7

Slide 7 text

The Problem It’s a solved problem for ADTs L. Maranget, Warnings for pattern matching, Journal of Functional Programming, 2007 How to handle growing complexity of type systems? • GADTs • subtyping • mixins • typecase • path-dependent types • union types • ... A new algorithm based on space algebra • bring complexity under control 3

Slide 8

Slide 8 text

The Theoretical Limits

Slide 9

Slide 9 text

Computability: Undecidable The compiler doesn’t know that a2 – 2ab + b2 + 1 = (a – b)2 + 1 > 0. (x, y) match { case (a, b) if a*a - 2*a*b + b*b + 1 > 0 => true } 4

Slide 10

Slide 10 text

Computability: Undecidable The compiler doesn’t know that a2 – 2ab + b2 + 1 = (a – b)2 + 1 > 0. (x, y) match { case (a, b) if a*a - 2*a*b + b*b + 1 > 0 => true } Generally, exhaustivity check for pattern match with guards is undecidable. 4

Slide 11

Slide 11 text

Complexity Is following code exhaustive? sealed trait O; object A extends O; object B extends O tuple match { case (A, A, A, A, A, _, _, _, _, _, _, _, _, _, _) => 1 case (B, _, _, _, _, A, A, A, A, _, _, _, _, _, _) => 2 case (_, B, _, _, _, B, _, _, _, A, A, A, _, _, _) => 3 case (_, _, B, _, _, _, B, _, _, B, _, _, A, A, _) => 4 case (_, _, _, B, _, _, _, B, _, _, B, _, B, _, A) => 5 case (_, _, _, _, B, _, _, _, B, _, _, B, _, B, B) => 6 } 5

Slide 12

Slide 12 text

Complexity Is following code exhaustive? sealed trait O; object A extends O; object B extends O tuple match { case (A, A, A, A, A, _, _, _, _, _, _, _, _, _, _) => 1 case (B, _, _, _, _, A, A, A, A, _, _, _, _, _, _) => 2 case (_, B, _, _, _, B, _, _, _, A, A, A, _, _, _) => 3 case (_, _, B, _, _, _, B, _, _, B, _, _, A, A, _) => 4 case (_, _, _, B, _, _, _, B, _, _, B, _, B, _, A) => 5 case (_, _, _, _, B, _, _, _, B, _, _, B, _, B, B) => 6 } (B, A, B, A, A, B, B, B, A, B, A, A, B, B, B) and more 5

Slide 13

Slide 13 text

Complexity: NP-Complete Idea: transform SAT of CNFs to exhaustivity check problems. For example, P = (p1 ∨ ¬p3 ) ∧ (p2 ∨ p3 ) can be transformed to following code C: sealed trait O object T extends O object F extends O (x, y, z) match { case (T, _, F) => case (_, T, T) => } 6

Slide 14

Slide 14 text

Complexity: NP-Complete Idea: transform SAT of CNFs to exhaustivity check problems. For example, P = (p1 ∨ ¬p3 ) ∧ (p2 ∨ p3 ) can be transformed to following code C: sealed trait O object T extends O object F extends O (x, y, z) match { case (T, _, F) => case (_, T, T) => } C unexhaustive ⇐⇒ (x = F ∨ z = T) ∧ (y = F ∨ z = F) satisfiable 6

Slide 15

Slide 15 text

Complexity: NP-Complete Idea: transform SAT of CNFs to exhaustivity check problems. For example, P = (p1 ∨ ¬p3 ) ∧ (p2 ∨ p3 ) can be transformed to following code C: sealed trait O object T extends O object F extends O (x, y, z) match { case (T, _, F) => case (_, T, T) => } C unexhaustive ⇐⇒ (x = F ∨ z = T) ∧ (y = F ∨ z = F) satisfiable ⇐⇒ P satisfiable 6

Slide 16

Slide 16 text

The New Algorithm

Slide 17

Slide 17 text

The Idea • Types and patterns can be thought as spaces of values • types: the values that inhabit the type • patterns: the values that can be matched by the pattern 7

Slide 18

Slide 18 text

The Idea • Types and patterns can be thought as spaces of values • types: the values that inhabit the type • patterns: the values that can be matched by the pattern • Some spaces can be decomposed into smaller spaces • Boolean, Int | Boolean, Option[Int] 7

Slide 19

Slide 19 text

The Idea • Types and patterns can be thought as spaces of values • types: the values that inhabit the type • patterns: the values that can be matched by the pattern • Some spaces can be decomposed into smaller spaces • Boolean, Int | Boolean, Option[Int] • There can be operations on spaces • intersection, subtraction, etc 7

Slide 20

Slide 20 text

Spaces Definition: 1. O is an empty space. 8

Slide 21

Slide 21 text

Spaces Definition: 1. O is an empty space. 2. T (T) is a type space of type T. 8

Slide 22

Slide 22 text

Spaces Definition: 1. O is an empty space. 2. T (T) is a type space of type T. 3. If s1, s2, · · · are spaces, then s1 | s2 | ... is a union space. 8

Slide 23

Slide 23 text

Spaces Definition: 1. O is an empty space. 2. T (T) is a type space of type T. 3. If s1, s2, · · · are spaces, then s1 | s2 | ... is a union space. 4. If s1, s2, · · · , sn are spaces and K is a constructor type, then K (K, s1, s2, ..., sn) is a constructor space. 8

Slide 24

Slide 24 text

Spaces Definition: 1. O is an empty space. 2. T (T) is a type space of type T. 3. If s1, s2, · · · are spaces, then s1 | s2 | ... is a union space. 4. If s1, s2, · · · , sn are spaces and K is a constructor type, then K (K, s1, s2, ..., sn) is a constructor space. 8

Slide 25

Slide 25 text

Spaces Definition: 1. O is an empty space. 2. T (T) is a type space of type T. 3. If s1, s2, · · · are spaces, then s1 | s2 | ... is a union space. 4. If s1, s2, · · · , sn are spaces and K is a constructor type, then K (K, s1, s2, ..., sn) is a constructor space. For example: • T (Int) is the space for Int • K (Some, T (Int)) is the space for Some(_: Int) • T (Int) | T (Boolean) is the space for Int | Boolean 8

Slide 26

Slide 26 text

Reformulation of Exhaustivity Check Problem The problem of exhaustivity check in terms of spaces: Is the space T (T), where T is the type of the value to be matched against, a subspace of the union of spaces covered by all the pattern clauses? 9

Slide 27

Slide 27 text

Reformulation of Exhaustivity Check Problem The problem of exhaustivity check in terms of spaces: Is the space T (T), where T is the type of the value to be matched against, a subspace of the union of spaces covered by all the pattern clauses? Example: val o: Option[Int] = ... o match { case Some(x) => x case None => 0 } 9

Slide 28

Slide 28 text

Reformulation of Exhaustivity Check Problem The problem of exhaustivity check in terms of spaces: Is the space T (T), where T is the type of the value to be matched against, a subspace of the union of spaces covered by all the pattern clauses? Example: val o: Option[Int] = ... o match { case Some(x) => x case None => 0 } Is T (Option[Int]) a subspace of K (Some, T (Int)) | T (None.type)? 9

Slide 29

Slide 29 text

The Decoupling The Generic Part (abstract space algebra): • s1 ⪯ s2: whether s1 is subspace of s2 • s . = O: whether s1 is equal to the empty space • s1 ⊓ s2: intersection of two spaces • s1 ⊖ s2: subtraction of two spaces The Concrete Part (APIs to the type system): • T1 <: T2: whether T1 is a subtype of T2 • sig(K): get parameter types of the constructor type K • D?(T): whether the type T is decomposable • D(T): decompose the type T into a union of subspaces • P(p): projects a pattern p to a space 10

Slide 30

Slide 30 text

Definition of Subspace (⪯) Definition (Subspace) s1 ⪯ s2 if and only if s1 ⊖ s2 . = O Notations: • s . = O: equality with the empty space • s1 ⊖ s2: subtraction of two spaces 11

Slide 31

Slide 31 text

Definition of Equality (s . = O) No need for a general theory of space equality. O . = O 12

Slide 32

Slide 32 text

Definition of Equality (s . = O) No need for a general theory of space equality. O . = O T (T) . = O if D?(T) ∧ D(T) . = O 12

Slide 33

Slide 33 text

Definition of Equality (s . = O) No need for a general theory of space equality. O . = O T (T) . = O if D?(T) ∧ D(T) . = O s1 | s2 | · · · . = O if ∀i.si . = O 12

Slide 34

Slide 34 text

Definition of Equality (s . = O) No need for a general theory of space equality. O . = O T (T) . = O if D?(T) ∧ D(T) . = O s1 | s2 | · · · . = O if ∀i.si . = O K (K, s1, s2, · · · ) . = O if ∃i.si . = O 12

Slide 35

Slide 35 text

Definition of Intersection (s1 ⊓ s2) 1 O ⊓ x = O 2 x ⊓ O = O 3 T (T1) ⊓ T (T2) = T (T1) if T1 <: T2 4 T (T1) ⊓ T (T2) = T (T2) if T2 <: T1 5 T (T) ⊓ K (K, s1, · · · ) = K (K, s1, · · · ) if K <: T 6 K (K, s1, · · · ) ⊓ T (T) = K (K, s1, · · · ) if K <: T 7 (s1 | s2 | · · · ) ⊓ x = s1 ⊓ x | s2 ⊓ x | · · · 8 x ⊓ (s1 | s2 | · · · ) = x ⊓ s1 | x ⊓ s2 | · · · 9 K (K, s1, · · · ) ⊓ K (K, w1, · · · ) = K (K, s1 ⊓ w1, s2 ⊓ w2, · · · ) 10 T (T) ⊓ x = D(T) ⊓ x if D?(T) 11 x ⊓ T (T) = x ⊓ D(T) if D?(T) 12 a ⊓ b = O otherwise 13

Slide 36

Slide 36 text

Definition of Intersection (s1 ⊓ s2) 1 O ⊓ x = O 2 x ⊓ O = O 3 T (T1) ⊓ T (T2) = T (T1) if T1 <: T2 4 T (T1) ⊓ T (T2) = T (T2) if T2 <: T1 5 T (T) ⊓ K (K, s1, · · · ) = K (K, s1, · · · ) if K <: T 6 K (K, s1, · · · ) ⊓ T (T) = K (K, s1, · · · ) if K <: T 7 (s1 | s2 | · · · ) ⊓ x = s1 ⊓ x | s2 ⊓ x | · · · 8 x ⊓ (s1 | s2 | · · · ) = x ⊓ s1 | x ⊓ s2 | · · · 9 K (K, s1, · · · ) ⊓ K (K, w1, · · · ) = K (K, s1 ⊓ w1, s2 ⊓ w2, · · · ) 10 T (T) ⊓ x = D(T) ⊓ x if D?(T) 11 x ⊓ T (T) = x ⊓ D(T) if D?(T) 12 a ⊓ b = O otherwise 13

Slide 37

Slide 37 text

Intersection of two constructor spaces K (K, s1, · · · ) ⊓ K (K, w1, · · · ) = K (K, s1 ⊓ w1, s2 ⊓ w2, · · · ) (None, Some) ⊓ (Some, Some) 14

Slide 38

Slide 38 text

Intersection of two constructor spaces K (K, s1, · · · ) ⊓ K (K, w1, · · · ) = K (K, s1 ⊓ w1, s2 ⊓ w2, · · · ) (None, Some) ⊓ (Some, Some) = (None ⊓ Some, Some ⊓ Some) 14

Slide 39

Slide 39 text

Intersection of two constructor spaces K (K, s1, · · · ) ⊓ K (K, w1, · · · ) = K (K, s1 ⊓ w1, s2 ⊓ w2, · · · ) (None, Some) ⊓ (Some, Some) = (None ⊓ Some, Some ⊓ Some) = (O, Some) 14

Slide 40

Slide 40 text

Intersection of two constructor spaces K (K, s1, · · · ) ⊓ K (K, w1, · · · ) = K (K, s1 ⊓ w1, s2 ⊓ w2, · · · ) (None, Some) ⊓ (Some, Some) = (None ⊓ Some, Some ⊓ Some) = (O, Some) = O 14

Slide 41

Slide 41 text

Intersection of two constructor spaces K (K, s1, · · · ) ⊓ K (K, w1, · · · ) = K (K, s1 ⊓ w1, s2 ⊓ w2, · · · ) (None, Some) ⊓ (Some, Some) = (None ⊓ Some, Some ⊓ Some) = (O, Some) = O (None, Some) ⊓ (_, _) 14

Slide 42

Slide 42 text

Intersection of two constructor spaces K (K, s1, · · · ) ⊓ K (K, w1, · · · ) = K (K, s1 ⊓ w1, s2 ⊓ w2, · · · ) (None, Some) ⊓ (Some, Some) = (None ⊓ Some, Some ⊓ Some) = (O, Some) = O (None, Some) ⊓ (_, _) = (None ⊓ _, Some ⊓ _) 14

Slide 43

Slide 43 text

Intersection of two constructor spaces K (K, s1, · · · ) ⊓ K (K, w1, · · · ) = K (K, s1 ⊓ w1, s2 ⊓ w2, · · · ) (None, Some) ⊓ (Some, Some) = (None ⊓ Some, Some ⊓ Some) = (O, Some) = O (None, Some) ⊓ (_, _) = (None ⊓ _, Some ⊓ _) = (None, Some) 14

Slide 44

Slide 44 text

Definition of Subtraction (s1 ⊖ s2) 1 O ⊖ x = O 2 x ⊖ O = x 3 T (T1) ⊖ T (T2) = O if T1 <: T2 4 T (K) ⊖ K (K, s1, · · · ) = K (K, map T sig(K)) ⊖ K (K, s1, · · · ) 5 (s1 | s2 | · · · ) ⊖ x = s1 ⊖ x | s2 ⊖ x | · · · 6 x ⊖ (s1 | s2 | · · · ) = x ⊖ s1 ⊖ s2 ⊖ · · · 7 K (K, s1, · · · ) ⊖ T (T) = O if K <: T 8 K (K, s1, · · · ) ⊖ K (K, w1, · · · ) = O if ∀i.si ⪯ wi 9 K (K, s1, · · · ) ⊖ K (K, w1, · · · ) = K (K, s1, · · · ) if ∃i.si ⊓ wi . = O 10 K (K, s1, · · · ) ⊖ K (K, w1, · · · ) = K (K, s1 ⊖ w1, s2, · · · ) | K (K, s1, s2 ⊖ w2, · · · ) | · · · 11 T (T) ⊖ x = D(T) ⊖ x if D?(T) 12 x ⊖ T (T) = x ⊖ D(T) if D?(T) 13 a ⊖ b = a otherwise 15

Slide 45

Slide 45 text

Definition of Subtraction (s1 ⊖ s2) 1 O ⊖ x = O 2 x ⊖ O = x 3 T (T1) ⊖ T (T2) = O if T1 <: T2 4 T (K) ⊖ K (K, s1, · · · ) = K (K, map T sig(K)) ⊖ K (K, s1, · · · ) 5 (s1 | s2 | · · · ) ⊖ x = s1 ⊖ x | s2 ⊖ x | · · · 6 x ⊖ (s1 | s2 | · · · ) = x ⊖ s1 ⊖ s2 ⊖ · · · 7 K (K, s1, · · · ) ⊖ T (T) = O if K <: T 8 K (K, s1, · · · ) ⊖ K (K, w1, · · · ) = O if ∀i.si ⪯ wi 9 K (K, s1, · · · ) ⊖ K (K, w1, · · · ) = K (K, s1, · · · ) if ∃i.si ⊓ wi . = O 10 K (K, s1, · · · ) ⊖ K (K, w1, · · · ) = K (K, s1 ⊖ w1, s2, · · · ) | K (K, s1, s2 ⊖ w2, · · · ) | · · · 11 T (T) ⊖ x = D(T) ⊖ x if D?(T) 12 x ⊖ T (T) = x ⊖ D(T) if D?(T) 13 a ⊖ b = a otherwise 15

Slide 46

Slide 46 text

Subtraction of two constructor spaces K (K, s1, · · · ) ⊖ K (K, w1, · · · ) = K (K, s1 ⊖ w1, s2, · · · ) | K (K, s1, s2 ⊖ w2, · · · ) | · · · val x, y: Option[Int] = ... (x, y) match { case (None, Some(_)) => true } 16

Slide 47

Slide 47 text

Subtraction of two constructor spaces K (K, s1, · · · ) ⊖ K (K, w1, · · · ) = K (K, s1 ⊖ w1, s2, · · · ) | K (K, s1, s2 ⊖ w2, · · · ) | · · · val x, y: Option[Int] = ... (x, y) match { case (None, Some(_)) => true } (_, _) ⊖ (None, Some(_)) = 16

Slide 48

Slide 48 text

Subtraction of two constructor spaces K (K, s1, · · · ) ⊖ K (K, w1, · · · ) = K (K, s1 ⊖ w1, s2, · · · ) | K (K, s1, s2 ⊖ w2, · · · ) | · · · val x, y: Option[Int] = ... (x, y) match { case (None, Some(_)) => true } (_, _) ⊖ (None, Some(_)) = (_ ⊖ None, _) | (_, _ ⊖ Some(_)) 16

Slide 49

Slide 49 text

Subtraction of two constructor spaces K (K, s1, · · · ) ⊖ K (K, w1, · · · ) = K (K, s1 ⊖ w1, s2, · · · ) | K (K, s1, s2 ⊖ w2, · · · ) | · · · val x, y: Option[Int] = ... (x, y) match { case (None, Some(_)) => true } (_, _) ⊖ (None, Some(_)) = (_ ⊖ None, _) | (_, _ ⊖ Some(_)) = (Some(_), _) | (_, None) 16

Slide 50

Slide 50 text

Subtraction of two constructor spaces K (K, s1, · · · ) ⊖ K (K, w1, · · · ) = K (K, s1 ⊖ w1, s2, · · · ) | K (K, s1, s2 ⊖ w2, · · · ) | · · · val x, y: Option[Int] = ... (x, y) match { case (None, Some(_)) => true } (_, _) ⊖ (None, Some(_)) = (_ ⊖ None, _) | (_, _ ⊖ Some(_)) = (Some(_), _) | (_, None) Naive formulation (_, _) ⊖ (None, Some(_)) = (_ ⊖ None, _ ⊖ Some(_)) 16

Slide 51

Slide 51 text

Subtraction of two constructor spaces K (K, s1, · · · ) ⊖ K (K, w1, · · · ) = K (K, s1 ⊖ w1, s2, · · · ) | K (K, s1, s2 ⊖ w2, · · · ) | · · · val x, y: Option[Int] = ... (x, y) match { case (None, Some(_)) => true } (_, _) ⊖ (None, Some(_)) = (_ ⊖ None, _) | (_, _ ⊖ Some(_)) = (Some(_), _) | (_, None) Naive formulation (_, _) ⊖ (None, Some(_)) = (_ ⊖ None, _ ⊖ Some(_)) = (Some(_), None) 16

Slide 52

Slide 52 text

An Assumption of the Algorithm Assumption A constructor type K cannot be a super type of other types. 17

Slide 53

Slide 53 text

An Assumption of the Algorithm Assumption A constructor type K cannot be a super type of other types. Otherwise, it’s unknown how to define the following: T (T) ⊖ K (K, s1, · · · ) = ? if T <: K K (K, s1, · · · ) ⊖ T (T) = ? if T <: K 17

Slide 54

Slide 54 text

An Assumption of the Algorithm Assumption A constructor type K cannot be a super type of other types. Otherwise, it’s unknown how to define the following: T (T) ⊖ K (K, s1, · · · ) = ? if T <: K K (K, s1, · · · ) ⊖ T (T) = ? if T <: K T (T) ⊓ K (K, s1, · · · ) = ? if T <: K K (K, s1, · · · ) ⊓ T (T) = ? if T <: K 17

Slide 55

Slide 55 text

An Assumption of the Algorithm Assumption A constructor type K cannot be a super type of other types. Otherwise, it’s unknown how to define the following: T (T) ⊖ K (K, s1, · · · ) = ? if T <: K K (K, s1, · · · ) ⊖ T (T) = ? if T <: K T (T) ⊓ K (K, s1, · · · ) = ? if T <: K K (K, s1, · · · ) ⊓ T (T) = ? if T <: K Note It’s possible to extend a case class in Scala, but it’s an anti-pattern! 17

Slide 56

Slide 56 text

Intricacy in the formalization Simple, but not trivial: • Union (|) is a type, while • Intersection (⊓) and subtraction (⊖) are functions Why? 18

Slide 57

Slide 57 text

Evaluation

Slide 58

Slide 58 text

Correctness • Implementation for Dotty 1 (400LOC VS. 1400LOC) • Pass regression test • Fix 13 open issues • No formal proof yet 1https://github.com/lampepfl/dotty/pull/1364 19

Slide 59

Slide 59 text

Performance Series I, S, V and T from Maranget’s paper(2007). 100 200 300 400 500 0 0.5 1 1.5 2 ·108 Series I dotty scala 4 6 8 10 107 108 109 1010 1011 1012 1013 Series S dotty scala 1 2 3 4 5 6 106 108 1010 1012 Series V dotty scala 0 5 10 15 20 106 107 108 109 1010 Series T dotty scala Figure 1: Performance comparison (time unit: ns) 20

Slide 60

Slide 60 text

Limitation The algorithm is ignorant of type constraints between constructor parameters. sealed trait Expr[T] case class IExpr(x: Int) extends Expr[Int] case class BExpr(b: Boolean) extends Expr[Boolean] def foo[T](x: Expr[T], y: Expr[T]) = (x, y) match { case (IExpr(_), IExpr(_)) => true case (BExpr(_), BExpr(_)) => false } 21

Slide 61

Slide 61 text

Limitation The algorithm is ignorant of type constraints between constructor parameters. sealed trait Expr[T] case class IExpr(x: Int) extends Expr[Int] case class BExpr(b: Boolean) extends Expr[Boolean] def foo[T](x: Expr[T], y: Expr[T]) = (x, y) match { case (IExpr(_), IExpr(_)) => true case (BExpr(_), BExpr(_)) => false } warning: match may not be exhaustive. It would fail on the following input: (BExpr(_), IExpr(_)), (IExpr(_), BExpr(_)) 21

Slide 62

Slide 62 text

Limitation The algorithm is ignorant of type constraints between constructor parameters. sealed trait Expr[T] case class IExpr(x: Int) extends Expr[Int] case class BExpr(b: Boolean) extends Expr[Boolean] def foo[T](x: Expr[T], y: Expr[T]) = (x, y) match { case (IExpr(_), IExpr(_)) => true case (BExpr(_), BExpr(_)) => false } warning: match may not be exhaustive. It would fail on the following input: (BExpr(_), IExpr(_)), (IExpr(_), BExpr(_)) Possible fix: ask typer to type check counterexamples in the case of GADTs. 21

Slide 63

Slide 63 text

Conclusion

Slide 64

Slide 64 text

Conclusion • Space algebra: intersection (⊓), subtraction (⊖), emptiness (s . = O) • Decoupling of generic algorithm from concrete type system • Simple, intuitive and easy to generate counterexamples • Works well for practical programs 22

Slide 65

Slide 65 text

Thank You! Questions? 22

Slide 66

Slide 66 text

Intricacy in the formalization Simple, but not trivial: • Union (|) is a type, while • Intersection (⊓) and subtraction (⊖) are functions Why? Union must be a type: • (Some, None) | (None, Some) 23

Slide 67

Slide 67 text

From Patterns to Spaces (P) The definition of the function P is the responsibility of concrete algorithms. Generally, following rules should be followed: P(x : T) = T (T) P(p1 | p2 | · · · ) = P(p1 ) | P(p2 ) | · · · P(K(p1 , p2 , · · · )) = K (K, P(p1 ), P(p2 ), · · · ) 24

Slide 68

Slide 68 text

Series I abstract sealed trait C case object C1 extends C case object C2 extends C case object C3 extends C case object C4 extends C case object C5 extends C c match { case C1 => 1 case C2 => 2 case C3 => 3 case C4 => 4 case C5 => 5 } 25

Slide 69

Slide 69 text

Series S sealed trait O object A extends O object B extends O tuple match { case (A, A, _, _, _, _, _, _) => 1 case (_, _, A, A, _, _, _, _) => 2 case (_, _, _, _, A, A, _, _) => 3 case (_, _, _, _, _, _, A, A) => 4 case (B, A, B, A, B, A, B, A) => 5 } 26

Slide 70

Slide 70 text

Series V sealed trait O object A extends O object B extends O tuple match { case (A, A, A, A, A, _, _, _, _, _, _, _, _, _, _) => 1 case (B, _, _, _, _, A, A, A, A, _, _, _, _, _, _) => 2 case (_, B, _, _, _, B, _, _, _, A, A, A, _, _, _) => 3 case (_, _, B, _, _, _, B, _, _, B, _, _, A, A, _) => 4 case (_, _, _, B, _, _, _, B, _, _, B, _, B, _, A) => 5 case (_, _, _, _, B, _, _, _, B, _, _, B, _, B, B) => 6 } 27

Slide 71

Slide 71 text

Series T sealed trait O object A extends O object B extends O tuple match { case (A, A, A, A, A) => 1 case (B, B, B, B, B) => 2 case (_, A, A, A, A) => 3 case (_, B, B, B, B) => 4 case (_, _, A, A, A) => 5 case (_, _, B, B, B) => 6 case (_, _, _, A, A) => 7 case (_, _, _, B, B) => 8 case (_, _, _, _, A) => 9 case (_, _, _, _, B) => 10 } 28

Slide 72

Slide 72 text

Why define subspace indirectly The difficulty is as follows: • Is (_, _) as subspace of (Some, None) | (None, Some) Subtraction seems unavoidable in such cases. 22