1 / 21

Dependently Typed Pattern Matching

Dependently Typed Pattern Matching. Hongwei Xi Boston University. Datatypes. Available in various functional programming languages such as SML and Haskell Convenience in programming Clarity in code. An Example: Random-Access Lists. Cons: O(log n) (Amortized: O(1))

tal
Download Presentation

Dependently Typed Pattern Matching

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Dependently Typed Pattern Matching Hongwei Xi Boston University

  2. Datatypes • Available in various functional programming languages such as SML and Haskell • Convenience in programming • Clarity in code

  3. An Example: Random-Access Lists • Cons: O(log n) (Amortized: O(1)) • Uncons: O(log n) (Amortized: O(1)) • Lookup operation: O(log n) • Update operation: O(log n)

  4. Datatype for Random Lists • datatype ‘a ralist = Nil | One of ‘a| Even of ‘a ralist * ‘a ralist| Odd of ‘a ralist * ‘a ralist • L1: x1, …,xn; L2: y1, …, ynEven(L1, L2): x1, y1, …, xn, yn • L1: x1, …,xn, xn+1; L2: y1, …, ynOdd(L1, L2): x1, y1, …, xn, yn, xn+1

  5. Some Inadequacies • Even should only be applied to two nonempty lists of equal length • Oddshould only be applied to two nonempty lists where the first list contains exactly one more element than the second one • Unfortunately, these invariants cannot be captured by the type system of ML

  6. Dependent Datatypes for Random Lists • datatype ‘a ralist with nat = Nil(0) | One(1) of ‘a| {n:pos} Even(n+n) of ‘a ralist(n) * ‘a ralist(n)| {n:pos} Odd(n+n+1) of ‘a ralist(n+1) * ‘a ralist(n) • For instance, Even is given the type:{n:pos} ‘a ralist(n) * ‘a ralist(n) -> ‘a ralist(n+n)

  7. uncons in Dependent ML(DML) • fun(‘a) uncons (One x) = (x, Nil)| uncons (Even (l1, l2)) = (case uncons l1 of (x, Nil) => (x, l2) | (x, l1) => (x, Odd (l2, l1))| uncons (Odd (l1, l2)) = let val (x, l1) = uncons l1 in (x, Even (l2, l1)) endwithtype {n:pos} ‘a ralist(n) -> ‘a * ‘a ralist(n-1)

  8. Pattern Matching in DML • Nondeterministic at compile-time • Sequential at run-time • This can cause an annoying problem in DML: the previous code for uncons does not type-check

  9. Mutually Disjoint Patterns • Note that:nondeterministic pattern matching is the same as sequential pattern matching if all patterns are disjoint • We can manually expand patterns into disjoint ones, but this may be inconvenient and error-prone

  10. An Example of Expansion • (case uncons l1 of (x, Nil) => (x, l2) | (x, l1) => (x, Odd (l2, l1))is expanded into(case uncons l1 of (x, Nil) => (x, l2) | (x, l1 as One _) => (x, Odd (l2, l1)) | (x, l1 as Even _) => (x, Odd (l2, l1)) | (x, l1 as Odd _) => (x, Odd (l2, l1))

  11. The Problem • Given patterns p, p1, …, pn,we intend to find a list patterns p’1, …, p’n’ such that a value v matches p but none of pi if and only if it matches one of p’j. • Note that p’1, …, p’n’ need not be disjoint. • An algorithm that generates the least n’ is said to be optimal.

  12. The result • An algorithm, which is essentially based upon Laville’s work, is presented and proven to be optimal. • Note that this is an exponential algorithm. • We do handle datatypes with infinitely many constructors (integers).

  13. A Motivating Example • fun restore (R(R t, y, c), z, d) = R(B t, y, B(c, z, d)) | restore (R(a, x, R(b, y, c)), z, d) = R(B (a, x, b), y, B(c, z, d)) | restore (a, x, R(R(b, y, c), z, d)) = R(B (a, x, b), y, B(c, z, d)) | restore (a, x, R(b, y, R t)) = R(B (a, x, b), y, B t) | restore t == B t (* == indicates the need for resolving sequentiality *)withtype … • The last clause in the above definition needs to be expanded into 36 ones in order to type-check.

  14. Exhaustiveness of Patterns • datatype ‘a list with nat = nil(0) | {n:nat} cons(n+1) of ‘a * ‘a list(n) • fun(‘a, ‘b) zip ([], []) = [] | zip (x :: xs, y :: ys) = (x, y) :: zip (xs, ys)withtype {n:nat} ‘a list(n) * ‘b list(n) -> (‘a * ‘b) list(n) • The pattern matching clauses in the definition of zip is exhaustive: neither ([], _ :: _) nor (_ :: _, []) can have type ‘a list(n) * ‘b list(n) for any natural number n.

  15. Exhaustiveness of Patterns • fun(‘a) nth_safe (0, x :: _) = x| nth_safe (i, _ :: xs) = nth_safe (i-1, xs)withtype {i:nat, n:nat | i < n} int(i) * ‘a list(n) -> ‘a • The pattern matching clauses are also exhaustive since …

  16. Pat = (_, _) Pos = o.0 1 Pat = ([], _) Pos = o.1 Pat = (_ :: _, _) Pos = o.1 2 3 Pat = ([], []) Pat = ([], _ :: _) Pat = (_ :: _, []) Pat = (_ :: _, _ ::_) 4 5 6 7 Tag Check Elimination

  17. Interpreter (I) • sort typ = Int | Bool | Fun of typ * typ • sort ctx = nil | :: of typ * ctx • datatype exp = Int of int | Bool of bool| Add of exp * exp | Sub of exp * exp| Eq of exp * exp | If of exp * exp * exp| One | Shift of exp | lam of exp| App of exp * exp | Fix of exp

  18. Interpreter (II) • We can refine exp with a type indes expression of sort typ * ctx:Add: {c:ctx} exp(Int, c) * exp (Int, c) -> exp (Int, c)One:{t:typ,c:ctx} exp(t, t :: c))Shift:{ta:typ,tb:typ,c:ctx} exp(ta,c) -> exp(ta, tb :: c)Lam:{ta:typ,tb:typ,c:ctx} exp(tb, ta :: c) -> exp (Fun(ta, tb), c)…

  19. Interpreter (III) • fun evaluate e = eval (e, [])withtype {t:typ} exp(t, nil) -> value(t)and eval (Zero e, env) = let val ValInt i = eval (e, env) in ValBool (i = 0) end… …

  20. Untagged Representation • Obviously, there is no need for tags if we never do tag-checking on the values of a particular datatype • However, garbage collection makes things much more difficult

  21. Conclusion • Dependent datatypes can more accurately model data structures • More program errors can be detected at compile-time • Code becomes more robust • This is a case when safer code runs faster

More Related