Functional List C and Data Structures Baojian Hua
Functional List C and Data Structures Baojian Hua bjhua@ustc. edu. cn
Recap n The extensible array-based implementation of linear list: n may be too slow n n may waste too much space n n insert or delete operations involve data movement only a small portion of the allocated space is occupied with data General computer science idea: n “pay as you go”
Polymorphic Abstract Data Types in C // recall the “List_t” ADT: #ifndef LIST_H #define LIST_H typedef void *poly; typedef struct List_t *List_t; List_t List_new (); int List_length (List_t l); poly List_nth (List_t l, int n); void List_insert (List_t l, poly x, int i); poly List_delete (List_t l, int i); void List_foreach (List_t l, void (*f)(poly)); #endif
Functional List n A functional list is inductively defined: n n case #1: it is empty, or case #2: a head element and a tail of another smaller list n n n (x 1, (x 2, (x 3, …))) head: x 1; tail: (x 2, (x 3, …)) Next, we sometimes say “list” for simplicity
Mathematical Notation n A functional list is inductively defined: n n case #1: it is empty, or case #2: a head element and a tail of another smaller list
Data Structure n We use a pointer “p” to point to a list: n n p case #1: empty, p==0 (or NULL) case #2: head: : tail, x 0 x 1 x 2 x 3 …
Implementation // Turn the above figure into C, we have: // in file “list. c” #include <stdlib. h> #include “list. h” struct List_t { poly data; List_t next; }; list data next …
Create a list // “List_new” returns an empty list List_new () { return 0; }
Add a new Head List_t List_concat (poly data, List_t l) { List_t temp = malloc (sizeof(*temp)); temp->data = data; temp->next = l; return temp; } l temp data next …
Operation: “foreach” void List_foreach (List_t l, void (*f)(poly)) { switch ((int)l) { case 0: return; default: f (l->data); List_foreach (l->next, f); // tail recursion } }
Operation: “length” l data next …
Operation: “length” int List_length (List_t l) { switch((int)l) { case 0: return 0; default: return 1 + List_length (l->next); } l data next …
Operation: “nth” l data next …
Operation: “nth” poly List_nth (List_t l, int n) { switch ((int)l) { case 0: error (“empty list”); default: if (0==n) return l->data; else return List_nth (l->next, n-1); } } l data next …
Operation: “delete(l, n)” l data next …
Operation: “delete” List_t List_delete (List_t l, int n) { if (0==l || n<0) error (“…”); if (0==n) return l->next; return List_concat (l->data, … n. List_delete (l->next, 1)); }
Operation: “insert(l, x, n)” l data next …
Operation: “insert” List_t List_insert (List_t l, poly x, int n) { if (0==n) return List_concat(x, l); if (0==l) error (“…”); return List_concat(l->data, List_insert(l->next, x, n 1); } l … data next
Summary n Functional programming: n long history, even older than C n n for long time considered impractical n n stem from mathematics John Macathy’s LISP (60’s) and later Scheme, ML, Haskell, Java. Script, etc. efficiency issue renew industry’s interest in recent decade n n e. g. , F# from Microsoft good for parallel, multi-core, etc.
Summary n Pros: n good for programmer n n n data structures are persistent elegant, easy to write, easy to maintain, easy to debug Cons: n (maybe) bad for machine n n n code maybe too slow both MS vc and GCC are bad in dealing this demand better compiler supports
- Slides: 20