Post on 31-Dec-2015
Our Goal How to write data types (math.) via
inductive definitions? How to turn inductive definitions
into data structures? How to write algorithms operated
on these data structures? How to argue the correctness of
the algorithms?
Dead-simple Example: nat// Data types:
1. A zero, or
2. a number follow another nat.
// Rewrite into inductive definition form:
nat -> Zero
-> Succ nat
// Q: how to turn this into data structures?
Tagged Union in C// Rewrite into inductive definition form:nat -> Zero -> Succ nat
typedef natStruct *nat;struct natStruct { enum natKind {Zero, Succ} kind; union {
nat n; } u;};
u
kind
Interface#ifndef NAT_H#define NAT_H
typedef natStruct *nat;struct natStruct { enum natKind {Zero, Succ} kind; union {
nat n; } u;};
Interface Continuednat newNatZero ();nat newNatSucc (nat n);nat natAdd (nat n1, nat n2);int natToInt (nat n);
#endif
Generate natnat newNatZero (){ nat t = (nat)malloc (sizeof (*t)); t->kind = Zero; return t;}
nat newNatSucc (nat n){ nat t = (nat)malloc (sizeof (*t)); t->kind = Succ; t->u.n = n; return t;}
u
kind
nat -> Zero -> Succ nat
Example: 33: Succ(Succ(Succ(Zero)));
three = newNatSucc( newNatSucc( newNatSucc( newNatZero())));
u
kind
u
kind
u
kind
u
kindthree
Example: 33: Succ(Succ(Succ(Zero)));
three = newNatSucc( newNatSucc( newNatSucc( newNatZero())));
u
Zero
u
Succ
u
Succ
u
Succthree
Additionn1 n2 = { n2, if n1==Zero;⊕ { Succ (m n2), if n1==Succ(m).⊕
nat natAdd (nat n1, nat n2){ switch (n1->kind) { case Zero: return n2; case Succ: return newNatSucc (natAdd (n1->u.n, n2)); default: error (…); } return NULL;}
u
kind
toInttoInt(n) = { 0, if n==Zero; { 1+toInt(m), if n1==Succ(m).
int natToInt (nat n){ switch (n->kind) { case Zero: return 0; case Succ: return 1+(natToInt(n->u.n)); default: error (…); } return -1;}
u
kind
Linked List// Data types:
1. An empty list, or
2. a node, followed by another list.
// Rewrite into inductive definition form:
list -> Empty
-> Cons T, list
// Q: how to turn this into data structures?
Tagged Union in C// Rewrite into inductive definition form:list -> Empty -> Cons (T, list)typedef listStruct *list;struct listStruct { enum listKind {Empty, Cons} kind; union {
struct { void *data; list next; } node; } u;};
u
kind
Interface#ifndef LIST_H#define LIST_H
typedef listStruct *list;struct listStruct { enum listKind {Empty, Cons} kind; union {
struct { void *data; list next; } node; } u;};
Interface Continuedlist newListEmpty ();list newListCons (void *data, list next);int length (list l);list insertHead (list l, void *data);list insertTail (list l, void *data);
#endif
Generate a Listlist newListEmpty (){ list t = (list)malloc (sizeof (*t)); t->kind = Empty; return t;}list newListCons (void *data, list l){ list t = (list)malloc (sizeof (*t)); t->kind = Cons; t->u.node.data = data; t->u.node.next = l; return t;}
u
kind
list -> Empty -> Cons (T, list)
Lengthlength(l) = { 0, if l==Empty; { 1+length(m), if l==Cons (T, m)
int length (list l){ switch (l->kind) { case Empty: return 0; case Cons: return 1 + length(l->u.node.next); default: error (…); } return -1;}
u
kind
Insert at Headf(d, l) = Cons (d, l)
list insertHead (void *d, list l){ return newListCons (d, l);} u
kind
Insert at Tailf(d, l) = { Cons (d, l), if l==Empty; { Cons (x, f(d, m)), if l==Cons(x, m).list insertTail (void *d, list l){ switch (l->kind) { case Empty: return newListCons (d, l); case Cons: return newListCons (l->u.node.data, insertTail (d, l->u.node.next)); default: error (…); } return NULL;}
u
kind
How can you argue this is correct?
How does it Work?
u
Empty
3
Cons
6
Cons
4
Conslist
insert 9 at tail
u
Empty
9
Cons
3
Cons
6
ConsnewList
4
Cons
Persistent Data Structures Data structures never change once
created you may want to compare the list here with
the ones we discussed in Lab #1 Good for many purpose
reason the correctness of the code local debugging important in emerging fields such as
concurrent programming or multi-core
Functional Programming Stemming from mathematics
Church and Turing, etc. Programming (and the resulting code) just
behaves like writing mathematical functions persistent data structures h recursive functions
An important programming idioms I personally love it more than procedural, OO,
generic, etc. Stepping into industry
Such as F# from M…S…
Local Class Hierarchyabstract class List<X> {}
class ListEmpty<X> extends List<X> {}
class ListCons<X> extends List<X>{ X data; List<X> next;
ListCons (X data, List<X>next) {…}}
Ugly Castclass Match<X>{ public int size (List<X> l) { if (l instanceof ListEmpty<X>) return 0; else if (l instanceof ListCons<X>) …; else …; }}// Or the visitor pattern
In C++template <typename X>class List{public: virtual void foo()=0;};
template <typename X>class ListEmpty: public List<X> {public: void foo (){};};