Reasoning in Functional Programming - PowerPoint PPT Presentation

1 / 25
About This Presentation
Title:

Reasoning in Functional Programming

Description:

... which happens to be n, as long as we forget that it has that property ... for a type that actually forgets which concrete kind of Vector it is dealing with: ... – PowerPoint PPT presentation

Number of Views:22
Avg rating:3.0/5.0
Slides: 26
Provided by: SMK86
Category:

less

Transcript and Presenter's Notes

Title: Reasoning in Functional Programming


1
Reasoning in Functional Programming
  • Stefan Kahrs

2
Traditional Reasoning in FP
  • equational reasoning
  • we write equations, we use them as equations
  • ADTs via encapsulation, typically at module level
    (as in other PL)
  • programs vs. specifications
  • waterfall refinement model
  • I will largely ignore this tradition
  • for a good book on the subject see
  • Bird, de Moor Algebra of Programming

3
Just one example
  • consider
  • (map f xs) ys
  • foldr () ys (map f xs)
  • (foldr () ys . map f) xs
  • foldr (().f) ys xs
  • The third equation uses one form of Reynolds
    parametricity theorem, e.g. that polymorphic
    functions behave like natural transformations

4
Type Theory
  • late 1960s, AUTOMATH project, automatising
    mathematics a form of typed l-calculus
  • properties are kept at type level, not (normally)
    through encapsulation but through more expressive
    type constructions
  • idea in a typed language, programs would be
    correct by construction

5
Influence of TT on languages
  • ML family powerful module language, higher-order
    parameterised modules
  • Haskell family
  • existential types
  • higher-order type variables
  • move from ML-polymorphism to Fw
  • Not directly influenced by Type Theory, but an
    observation in its spirit
  • expressive power of nested algebraic types

6
Once dismissed as useless...
  • data DList a Nil
  • Cons a (DList (a,a))
  • About a decade ago, I attended a lunchtime
    seminar talk in Edinburgh, in which the speaker
    (a professor, no less) mentioned that types like
    this cause a problem for type inference but are
    useless anyway.

7
However...
  • values of that type always contain 2n-1 elements
    of type a
  • something we can never achieve with sums of
    products and recursive types alone
  • it allows us to write lists with log-time access
    of elements
  • what made the difference is that we have a
    recursive type constructor, not merely a
    recursive type

8
Aside
  • type inference is affected by nested algebraic
    types, it requires a different treatment of
    recursion
  • in Standard ML, you can define these types but
    not the functions operating on them
  • in Haskell, you have to help the type checker by
    declaring types
  • in general, type inference w.r.t. this more
    complicated form of recursion is only
    semi-decidable

9
List Access for this type
  • select xs n sel xs n id
  • sel DList a -gt Int -gt (a-gtb)-gt b
  • sel Nil _ _ undefined
  • sel (Cons x xs) 0 f f x
  • sel (Cons x xs) n f
  • sel xs ((n-1)div2)
  • (if (n mod 20) then f.fst
  • else f.snd)

10
Comment
  • It is typical that functions which operated on
    nested types have a higher-order parameter which
    is modified during recursion
  • In practice it usually suffices to employ
    Haskells class system to supply this parameter
    implicitly

11
Example Fixed Length Vectors
hence (.) a -gt v a -gt Cons v a
  • data NIL a NIL
  • data CONS v a a . v a
  • data BuildVector v a
  • Vec (v a)
  • Inc (BuildVector (CONS v) a)
  • type Vector a BuildVector NIL a
  • typical for nested datatypes ho type variable
    with shape information is changed during recursion

12
Aside
  • it would be convenient if we could express Church
    numerals at type level then we could say
  • type VEC n a n CONS NIL a
  • to get vectors of length n
  • although the above is legal, we cannot
    instantiate it as intended as Haskell (ghc goes a
    bit further though) forbids to curry type
    abbreviations
  • instead, we move computations on types to the
    class system more later...

13
Programming with these...
  • example the snoc operation, adds an element at
    the end of a vector
  • class SNOC v where
  • snoc v a -gt a -gt Cons v a
  • instance SNOC NIL where
  • snoc NIL x x . NIL

14
Programming (cont)
  • instance SNOC v gt SNOC (CONS v) where
  • snoc (y.ys) x y . snoc ys x
  • instance SNOC v gt
  • SNOC (BuildVector v) where
  • snoc (Vec xs) x
  • Inc(Vec(snoc xs x))
  • snoc (Inc xs) x
  • Inc(snoc xs s)

15
Objection
  • isnt Vector just a slightly more complicated
    version of ordinary lists?
  • yes, but once you worked yourself inside a vector
    you are working with a data structure the size of
    which is known by its type

16
Problem
  • how do we write an append operation on vectors?
  • or, rather, we probably do know how to write it,
    but how do we write its type?
  • if we had the mentioned Church numerals we could
    say
  • append VEC n a -gt VEC m a -gt VEC (add n m) a
  • but we have not (although ghc...)

17
Multi-parameter classes
  • class App v w x v w -gt x where
  • append v a -gt w a -gt x a
  • instance App NIL v v where
  • append NIL xs xs
  • instance App v w x gt
  • App (Cons v) w (Cons x) where
  • append (x . xs) ys x . append xs ys

18
Creating a vector of length n...
  • ...for a program-internal number n is essentially
    impossible in Haskell, as Haskell has no
    value-dependent types
  • however...
  • we can create a vector of a fixed length, which
    happens to be n, as long as we forget that it has
    that property
  • ???

19
Two ways to do it
  • for our previous type Vector a, recursively
  • I leave this as an exercise for you, for later
  • for a type that actually forgets which concrete
    kind of Vector it is dealing with
  • data Any a
  • forall v. VECTOR v gt Any (v a)
  • Not Haskell98, but supported by Hugs/ghc

20
Explanation
  • data Any a
  • forall v. VECTOR v gt Any (v a)
  • This is a type with only one constructor, Any.
  • It has type (note that v is not in result)
  • VECTOR v gt (v a) -gt Any a
  • This is polymorphic in v when we apply Any, and
    generic in v when we pattern-match with it.
  • The VECTOR v gt bit works both ways.

21
Example
  • data Any a
  • forall v. VECTOR v gt Any (v a)
  • makevector a -gt Any a
  • makevector Any NIL
  • makevector (xxs) lf (makevector xs)
  • where
  • lf(Any xs) Any (x.xs)

22
Why the local function definition?
  • existential type variables must not escape a
    local definition, the result type either throws
    them away or captures them with another
    quantifier, as in this case
  • in addition, ghc (but not hugs) steadfastly
    refuses to introduce them in lets/wheres

23
What is this good for?
  • once we have created a value of this type we can
    unpack it with local functions
  • ... lf value ...
  • where lf(Any vs) work-with-vs
  • and then vs will be of some type v a, where the
    only thing we know about v is that it is of class
    VECTOR
  • ...and where would this be of use?

24
Example
  • turn a into v(w a), as long as the thing has
    matrix shape, and is non-empty otherwise error
  • data Anymatrix a
  • forall v w.(VECTOR v,VECTOR w)gt
  • Anymatrix(v(w a))
  • makematrix a -gt Anymatrix a
  • makematrix error unknown shape

25
Example, continued
  • makematrix xs lf (makevector xs)
  • where lf(Any xs) Anymatrix(xs . NIL)
  • makematrix (xsxss) lf (makematrix xss)
  • where lf(Anymatrix xss)
  • Anymatrix (fromList xs . xss)
  • Note fromList is an overloaded function in class
    VECTOR it creates us a Vector of exactly the
    needed length if the list was of the right
    length which of the overloaded functions to pick
    is determined by the shape of the matrix from the
    recursive call
Write a Comment
User Comments (0)
About PowerShow.com