Constructors Construct a value of a given type. Most languages provide kinds: Atomic: 1, 3.14159, “hello”, etc. Compound: apply a function to one or more components: 3::nil (1, 2, 3) {a = “x”, y = 239.0}
Patterns A pattern is one of: + a constant + a variable + a wildcard _ + a compound constructor applied to one or more (sub)patterns
Informal matching algorithm fun matches(left, right) = if left is a constant then if left = right then true else false else if left is a variable then true else if left is a wildcard then true else if left is a compound constructor then if right has same top-level constructor then if (each component of left matches each component of right) then true else false else (* left may not appear in a pattern! *) raise some kind of error
val 3 = 3; val 3 = 4; val _ = “walrus” val (3+5, x) = (8, 9); val ({baz=“hi”, foo=seal}, fish::nil) = ({foo=“bar”, baz=“hi”}, [827]); val [2,3,x] @ nil = 2::3::4::nil;
Patterns and functions - fun silly(0, y) = y | silly(x, y) = 1 + silly(x-1, y); val silly = fn : int * int -> int - val my_tuple = (3,4); val my_tuple = (3,4) : int * int - silly(my_tuple); val it = 7 : int
Example: reverse fun reverse(x) = if null(x) then nil else reverse(tl(x)) @ [hd(x)]; fun reverse(nil) = nil | reverse(x::xs) = reverse(xs) @ [x];
Tail-recursive transformation Create a nested helper function Use parameter(s) in the helper that mean(s) “the work done so far”: fun reverse(x) = let fun rev(nil, rev_so_far) = done | rev(x::xs, rev_so_far) = rev(xs, x::rev_so_far); in rev(x, nil) end;
C++ templates template <class T> class ListNode { private: T* hd; ListNode* tl; public: ListNode(T * head, ListNode * tail) : hd(head), tl(tail) {} T* head() { return hd; } ListNode* tail() { return tl; } };
Template instantiation class ListNode__int__ { private: int* hd; ListNode__int__* tl; public: ListNode__int__(int * head, ListNode__int__ * tail) : hd(head), tl(tail) {} int* head() { return hd; } ListNode__int__* tail() { return tl; } };
Template functions template <class List> int length(List * list) { if (list == NULL) { return 0; } else { return 1 + length(list->tail()); } cout << length< ListNode<int> >(nums); // USAGE
Weird template tricks // Overload length() int length(double x) { return int(x - 10); } class A { // Define strange type public: double tail() { return 10.0; } }; A my_a; // USE: What happens? int result = length<A>(&my_a); cout << result << endl;
Summary: C++ templates C++ templates are more permissive than ML polymorphism: more programs can be written using templates Expressiveness/permissiveness comes at a cost: type checking is less restrictive. Textual substitution incorporates little “semantic” information.