Lecture notes for COMP 105 (Programming Languages)

Table of Contents

16 Jan 2013: Introduction to Comp 105

p1161322 p1162423 p1162426 p1162936 p1162942 p1163333 p1163349 p1163501 p1164348 p1165015 p1165650 p1165857

What Programming Languages isn't

What if the course were called "Houses"?

The same thing for programming languages:

What Programming Languages is

If you're going to enjoy the course,

Why so many languages?

Topic of study: the stuff software is made of

Conclusion: make it easier to write programs that really work

What do the professionals say?

In public: a language should express computations

So, no more uncivilized low-level C, and no more C++ that no mortal being can understand

In the pub: professionals are keenly interested in their code

Your language can make you or break you.

What can you get out of Comp 105?

Bonus: preparation for advanced study (This course serves two audiences)

How will it work?

Intellectual tools you need to understand, evaluate, and use languages effectively

Notations of the trade (source of precision, further study)

Learn by doing:

Just as intellectually challenging as COMP 40, but in an entirely different direction.

Great languages begin with great features

Language shapes your thinking

There aren't that many great features, and you will see them over and over

You'll choose features, and therefore languages, to fit your needs

Some are more powerful than others

In Comp 105,

OK, what are the great ideas?

To say more with less (expressive power):

To promote reliability and reuse:

Describing it all precisely:

Course logistics and administration

Three lectures per week: 50% more cracks at tough ideas

Schedule is still a work in progress:

You must get my book

Homework will be frequent and challenging:

Both individual and pair work:

Questions and answers on Piazza

Other policies and procedures in handout and on web

Recursion: a review

Ways a recursive function could decompose a natural number n.

  1. Peel back one:

    n = 0
    n = m + 1,    m is also a natural number
  2. Split into two pieces:

    n = 0
    n = k + (n - k)    0 < k < n   (everything gets smaller)
  3. Sequence of decimal digits (see study problems on digits)

    n = d,               where 0 <= d < 10
    n = 10 * m + d,      where 0 <= d < 10 and m > 0

To do your homework problems, which I recommend starting today, you'll need to invent at least one more.

(Why start early? To put your back brain to work.)

18 Jan 2013: Abstract syntax, environments

p1185597 p1185598 p1185599 p1185600 p1185601 p1185602 p1185603

Announcements and Administration

What am I called?

Call me "Norman," "Professor Ramsey", or "Mister Ramsey." In a pinch, "Professor" will do.

Optional reading

Cultural enrichment: Paul Graham, especially the "Blub paradox"

Scheduling, pace, and size of homework

I am also trying to solve two of the most important problems identified by your predecessors:

We are working toward this.

For this reason, the first homework is tiny: I broke off a tiny piece and called it a homework assignment. It's there to get you moving quickly. Everything you need to think about is in Wednesday's discussion of recursive functions that consume natural numbers.

Arc of the homework

Looks something like this:

Assignment Difficulty
impcore one star
opsem two stars
scheme three stars
hofs four stars

And it's more or less four-star homeworks from there on out.

Lesson: don't make decisions based on the first couple of homeworks!

Quizzes!

Many will be announced in advance. Some will not. My goal in having quizzes is that you come to lecture prepared to engage more deeply with the ideas, techniques, and notations. For that reason I am counting quiz grades toward class participation.

Quizzes will start when I feel well enough to write some. Perhaps next week or the week after.

The role of lectures

You'll see:

In a 100-level course, you are responsible for your own learning

Thinking about programming languages

Where have we been and where are we going?

Last time: refresher on recursion. Go for homework!

This week: abstract syntax and operational semantics (next homework)

Abstract Syntax

Programming-languages people are wild about compositionality.

Example of compositionality: syntax (grammar)

Programming languages more orderly than natural language.

Example of non-compositionality

Open question: what are all the representations of a while loop?

(Answers on board)

Introducing our common framework

Our common framework

Goal: eliminate superficial differences

No new language ideas.

Imperative programming with an IMPerative CORE:

Idea of LISP syntax

Parenthesized prefix syntax:

Examples:

(+ 2 2)
(if (isbound? x rho) (lookup rho x) (error 99))

Syntactic structure of Impcore

Two syntactic categories: definitions, expressions (no statements!)

An Impcore program is a sequence of definitions

(define mod (m n) (- m (* n (/ m n))))

Compare

int mod (int m, int n) { 
  return m - n * (m / n); 
}

Impcore variable definition

Example

(val n 99)

Compare

int n = 99;

Also, expressions at top level (definition of it)

Impcore expressions

No statements means expression-oriented:

(if e1 e2 e3)
(while e1 e2)
(set x e)
(begin e1 ... en)
(f e1 ... en)

Each one has a value and may have side effects!

Functions are primitive (+ - * / = < > print)
or defined with (define f ...).

The only type of data is "machine integer" (deliberate oversimplification)

Scoping rules for Impcore

Scopes also called "name spaces"; we will call them "environments" because that's the pointy-headed theory term---and if you want to read some of the exciting papers, pointy-headed theory has to be second nature.

Names known in "environments"

Ways to talk about meanings of names:

Impcore vars in 2 environments: globals, formals

There are no local variables

Functions live in their own environment (not shared with variables)

Environmental abuse

Abuse of separate name spaces:

-> (val f 33)
33
-> (define f (x) (+ x x))
f
-> (f f)
66

Concrete syntax for Impcore

Definitions and expressions:

def ::= (val x exp)
     |  exp
     |  (define f (formals) e)
     |  (use filename)

exp ::= integer-literal
     |  variable-name
     |  (set x exp)
     |  (if exp1 exp2 exp3)
     |  (while exp1 exp2)
     |  (begin exp1 ... expn)
     |  (op exp1 ... expn)  

op ::= function-name | primitive-name

Abstract syntax

Exp = LITERAL (Value)
    | VAR     (Name)
    | SET     (Name name, Exp exp)
    | IFX     (Exp cond, Exp true, Exp false)
    | WHILEX  (Exp cond, Exp exp)
    | BEGIN   (Explist)
    | APPLY   (Name name, Explist actuals)

One kind of "application" for both user-defined and primitive functions.

Representing abstract syntax

typedef struct Exp *Exp;
typedef enum {
  LITERAL, VAR, SET, IFX, WHILEX, BEGIN, APPLY
} Expalt;        /* which alternative is it? */

struct Exp {  // only two fields: 'alt' and 'u'!
    Expalt alt;
    union {
        Value literal;
        Name var;
        struct { Name name; Exp exp; } set;
        struct { Exp cond; Exp true; Exp false; } ifx;
        struct { Exp cond; Exp exp; } whilex;
        Explist begin;
        struct { Name name; Explist actuals; } apply;
    } u;
};

Example AST for (f x (* y 3)) (using Explist)

Example Ast for (define abs (x) (if (< x 0) (- 0 x) x)) (using Namelist)

Trick question:

What's the value of (* y 3)? OK, what's its meaning?

23 Jan 2013: Operational semantics of Impcore

p1235604 p1235605

Announcments

Tonight's homework

Piazza:

Next homework:

Waiting list:

Bare possibility of an office our from me this afternoon.

With my help, Geoff Mainland put together some terrifying Beamer slides

25 Jan 2013: Inference rules of Impcore

p1255606 p1255607

Short homework review

I owe you an apology. Inductive structure was way harder than I realized. I broke a cardinal rule (always do all the problems before they are assigned).

Let's look at just one:

(binary 5) == 101
(binary 3) ==  11

What's the inductive structure of the input?

OK, moving on to contracts!

Inference rules

Return to Beamer slides

28 Jan 2013: Derivations and metatheory

p1285608 p1285609 p1285610 p1285611 p1285612 p1285613 p1285614 p1285615

Brand new Beamer slides on metatheory

Today: for every evaluation there is a derivation

Every proof ends in a single judgment form:

<e, xi, phi, rho> => <v, xi', phi, rho'>

As usual, prime means it might be different

In a real rule, show how it's different (or not)

Derivations have restricted compositionality:

Metatheory

When does an expression contain set? Well, we can just look at the syntax. Or we can make a proof system

TeX slide

and also

TeX slide

Notice that set is the only construct that changes the environment.

Let's prove a theorem:
TeX slide

30 Jan 2013: Introducing Scheme

p1305616 p1305617 p1305618 p1305619 p1305620 p1305621 p1305622 p1305623 p1305624 p1305625

Where have we been and where are we going?

A new way of thinking about recursion

*Structure of the input drives the structure of the code.

To discover recursive functions, write algebraic laws:

exp x 0 = 1
exp x (n + 1) = x * (exp x n)

Can you find a direction in which something gets smaller?

Another example:

binary 0 = 0
binary (2n + b) = binary n .. b

Right-hand sides in arithmetic?

binary (2n + b) = 10 * binary n + b

Which direction gets smaller? What's the code?

Lots of new math

No new programming-language ideas

Programming with assignments etc

Where are we going?

Recursion and composition:

For a new language, five powerful questions

As a lens for understanding, you can ask these questions about any language:

  1. What is the abstract syntax? What are the syntactic categories, and what are the terms in each category?

  2. What are the values? What do expressions/terms evaluate to?

  3. What environments are there? That is, what can names stand for?

  4. How are terms evaluated? What are the judgments? (What are the rules?)

  5. What's in the initial basis? Primitives and otherwise, what is built in?

Introduction to Scheme

Question 2: what are the values?

Two new kinds of data:

(The setting is Scheme)

Values of Scheme

Values are S-expressions.

Comforting lies:

An S-expression is a symbol or a literal integer or a literal Boolean or a list of S-expressions.

A list of S-expressions is either - the empty list '() - an S-expression followed by a list of S-expressions

Like any other abstract data type

N.B. creators + producers = constructors

No mutators in uScheme

S-expression observers

number?
symbol?
boolean?
null?

Focus on lists

Creators and producers: nil and cons

'()

(cons S' S)

More examples:

(cons 'a '())
(cons 'a '(b))

Note the literal '(b). (Not covered in class.)

Inductive definition of lists:
TeX slide

Observers: car, cdr, null?, pair? (also known as "first" and "rest", "head" and "tail", and many other names)

Algebraic laws of lists:

(null? '()) == #t
(null? (cons v vs)) == #f
(car (cons v vs)) == v
(cdr (cons v vs)) == vs

Combine creators/producers with observers

Recursive functions for recursive types

Inductively defined data type: smallest set satisfying this equation:

Inductive definition of lists:
TeX slide

Any list is therefore constructed with nil or with cons.

Example: length

1 Feb 2013: More kinds of functions, more examples

p2015626 p2015627 p2015628 p2015629 p2015630 p2015631 p2015632 p2015633 p2015634 p2015635

Announcements

Today's homework:

Scheme homework advice:

What's next

More truth about S-expressions and the functions that consume them

The truth about S-expressions:
TeX slide

Full S-expression example: equality

Polymorphic means "operating on values of many types"

uScheme provides primitive = that works on numbers, symbols, and Booleans, but never cons cells.
It is useful only for comparing atoms

Let's define equal?, which will identify isomorphic S-expressions, including lists as a special case.

Look at slide: what are the cases?

          *** Atoms and polymorphic equality (on SX) ***
(define atom? (x)
  (or (number? x) 
  (or (symbol? x) 
  (or (boolean? x) 
      (null? x)))))

(define equal? (s1 s2)
  (if (or (atom? s1) (atom? s2))
    (= s1 s2)
    (and (equal? (car s1) (car s2)) 
         (equal? (cdr s1) (cdr s2)))))

More list-consuming functions; first steps toward analyzing costs

What's hard: moving from a sequence of operations on elements to a single operation on a list. The good news: this is also your leverage.

Board:

List append

Sequential composition is associative:

xs .. e         = xs
e .. ys         = ys
(x .. xs) .. ys = x .. (xs .. ys)
xs .. (y .. ys) = (xs .. y) .. ys

That double dot is informal (advantage to the mathematicians)

  1. Identify the dots

  2. We don't have snoc

  3. Which equations look useful for writing append?

4 Feb 2013: Designing using algebraic laws; costs of functional programs

p2045636 p2045637 p2045638 p2045639 p2045640 p2045641 p2045642

Homework review

The operational-semantics homework

Review:

User-defined functions:
TeX slide

User-defined functions:
TeX slide

The Impcore homework

Question: why do we break code up into functions?

Proper documentation therefore looks like this:

Because the program does not contain set, parameters and results are sufficient---there is nothing else you have to understand.

Faults to correct when you write your uScheme homework:

Individual feedback is coming...

Return to algebraic laws

Board:

Using informal math notation, with .. for "followed by", we have these laws:

xs .. e         = xs
e .. ys         = ys
(x .. xs) .. ys = x .. (xs .. ys)
xs .. (y .. ys) = (xs .. y) .. ys

The underlying operations are append, cons, and snoc

What is it in Scheme notation? (See slide)

          *** Equations and function for append ***
(append '()         ys) == ys
(append (cons z zs) ys) == (cons z (append zs ys))

(define append (xs ys)
  (if (null? xs) ys
      (cons (car xs) (append (cdr xs) ys))))

Why does it terminate?

Other laws:

(append (list1 x) ys) = ???

The major cost center is cons

Allocation is the big cost.

How many cons cells are allocated?

List reversal

What about list reversal?

reverse '() = '()
reverse (x .. xs) = reverse xs .. reverse x = reverse xs .. x

And the code?

          *** Naive list reversal ***
(define reverse (xs)
   (if (null? xs) '()
       (append (reverse (cdr xs))
               (list1 (car xs)))))

How many cons cells are allocated?

The method of accumulating parameters

Let's try a new algebraic law:

reverse (x .. xs) .. zs = reverse xs .. x .. zs = reverse xs .. (cons x zs)
reverse '() .. zs       = zs

The code

          *** Reversal by accumulating parameters ***
(define revapp (xs zs)
   (if (null? xs) zs
       (revapp (cdr xs) (cons (car xs) zs))))

(define reverse (xs) (revapp xs '()))

Parameter zs is the accumulating parameter.
(A powerful, general technique.)

Association lists represent finite maps (not to be covered in class)

Implementation: list of key-value pairs

'((k1 v1) (k2 v2) ... (kn vn))

Picture with spine of cons cells, car, cdar, caar, cadar.

          *** A-list example ***
    -> (find 'Building '((Course 105) (Building Lane) 
                              (Instructor Ramsey)))
    Lane
    -> (val nr (bind 'Office 'Extension-006 
               (bind 'Courses '(105)
               (bind 'Email 'comp105-staff '()))))
    ((Email comp105-staff) (Courses (105)) (Office Extension-006))
    -> (find 'Office nr) 
    Extension-006
    -> (find 'Favorite-food nr)
    ()

Notes:

Algebraic laws of association lists

          *** Laws of assocation lists ***
(find k (bind k v l)) = v
(find k (bind k' v l)) = (find k l), provided k != k'
(find k '()) =  '() --- bogus!

6 Feb 2013: Let and lambda

p2065643 p2065644 p2065645 p2065646 p2065647

Where have we been and where are we going

Where we've been: lists, algebraic specifications, accumulating parameters (the hard stuff)

Why are lists so useful?

These "cheap and cheerful" representations are less efficient than balanced search trees, but are very easy to implement and work with---see the book.

The only thing new here is automatic memory management. Everything else you could do in C. (You can have automatic memory management in C as well.)

Where we're going: new language features

One easy and one hard

  1. let binding for local names

  2. First-class, nested, higher-order functions

Handy new feature of Scheme: let binding

          *** Introduce local names into environment ***
(let ((x1 e1)
      ...
      (xn en))
    e)

Evaluate e1 through en, bind answers to x1, ... xn

Also let* (one at a time) and letrec (local recursive functions)

Note that we really have definititions and it might be easier to read if McCarthy had actually used definition syntax, which you'll see in ML, Haskell, and other functional languages:

          *** What McCarthy should have done ***
(let ((val x1 e1)
      ...
      (val xn en))
   e)

From Impcore to uScheme

Things that should offend you about Impcore:

All these problems have one solution: lambda

Anonymous, first-class functions

From Church's lambda-calculus:

(lambda (x) (+ x x))

"The function that maps x to x plus x"

At top level, like define. (Or more accurately, define is a synonym for lambda.)

In general, \x.E or (lambda (x) E)

The ability to "capture" free variables is what makes it interesting:

(lambda (x) (+ x y))  ; means what??

First-class, nested functions

What matters is that y can be a parameter or let-bound variable of an enclosing functions.

First example: finding roots

          *** Function escapes! ***
-> (define to-the-n-minus-k (n k)
      (let
        ((x-to-the-n-minus-k (lambda (x) 
                                (- (exp x n) k))))
        x-to-the-n-minus-k))
-> (val x-cubed-minus-27 (to-the-n-minus-k 3 27))
-> (x-cubed-minus-27 2)
-19

to-the-n-minus-k is a higher-order function because it returns another (escaping) function as a result.

          *** No need to name the escaping function ***
-> (define to-the-n-minus-k (n k)
      (lambda (x) (- (exp x n) k)))



-> (val x-cubed-minus-27 (to-the-n-minus-k 3 27))
-> (x-cubed-minus-27 2)
-19


          *** Application: a zero-finder ***
(define findzero-between (f lo hi)
   ; binary search
   (if (>= (+ lo 1) hi)
       hi
       (let ((mid (/ (+ lo hi) 2)))
          (if (< (f mid) 0)
              (findzero-between f mid hi)
              (findzero-between f lo mid)))))
(define findzero (f) (findzero-between f 0 100))

findzero-between is also a higher-order function because it takes another function as an argument. But nothing escapes; you can do this in C.

          *** Cube root of 27 and square root of 16 ***
-> (findzero (to-the-n-minus-k 3 27))                                    
3
-> (findzero (to-the-n-minus-k 2 16))
4

8 February 2013: Snowstorm, class cancelled

11 February 2013: More higher-order functions

p2115648 p2115649 p2115650 p2115651 p2115652 p2115653 p2115654

Notes on where we've been, where we're going:

Return to escaping functions

Why this matters: if you have nested, escaping functions, you can apply all the programming technique you're about to learn

Go back to integers; they're simpler

          *** Review: an "escaping" function ***
-> (define to-the-n-minus-k (n k)
      (lambda (x) (- (exp x n) k)))

"Escape" means "outlive the activation in which the lambda was evaluated."

Escaping and lifetimes are some of those universal decisions every programmer has to think about.

Where are n and k stored???

C programmers do this explicitly with malloc

In a language with first-class, nested functions, part of the semantics of lambda

Escaping function represented by a closure:
TeX slide

          *** What's the picture for conjunction? ***
(define conjoin (p? q?)
   (lambda (x) (if (p? x) (q? x) #f)))

More Higher-order functions!

Preview: in math, what is the following equal to?

(f o g)(x) == ???

Another algebraic law, another function:

          *** Functions create new functions ***
-> (define o (f g) (lambda (x) (f (g x))))
-> (define even? (n) (= 0 (mod n 2)))
-> (val odd? (o not even?))
-> (odd? 3)
-> (odd? 4)

Don't forget `(o not null?)'

          *** Classic functional technique: Currying ***
-> (val positive? (lambda (y) (< 0 y)))
-> (positive? 3)
-> (val <-curried (lambda (x) (lambda (y) (< x y))))
-> (val positive? (<-curried 0)) 
                          ; "partial application"
-> (positive? 0)

No need to Curry by hand!:
TeX slide

No need to Curry by hand!:
TeX slide

What's the algebraic law for curry?

 ...   (curry f) ...    =  ... f ...

Keeping in mind all you can do with a function is apply it?

Bonus content not covered in class: Lambda as an abstraction barrier

          *** Bonus content: vulnerable variables? ***
-> (val seed 1)
-> (val rand (lambda ()
      (set seed (mod (+ (* seed 9) 5) 1024)))))
-> (rand)
14
-> (rand)
131
-> (set seed 1)
1
-> (rand)
14


          *** Bonus: Lambda as abstraction barrier! ***
-> (val mk-rand (lambda (seed)
     (lambda ()
       (set seed (mod (+ (* seed 9) 5) 1024))))))
-> (val rand (mk-rand 1))
-> (rand)
14
-> (rand)
131
-> (set seed 1)
error: set unbound variable seed
-> (rand)
160

Truth about S-expressions and functions consuming functions

Q: Can you do case analysis on a function?

A: No!

Q: So what can you do then?

A: Apply it!

Examples

Standard higher-order functions on lists

Review

Recursive function consuming A is related to proof about A

What we did last time:

What's coming on homework

Standard higher-order functions on lists

Goal: start with functions on elements, wind up with functions on lists

Capture common patterns of computation or algorithms

Folds also called reduce, accum, "catamorphism"

List search: exists?

Algorithm encapsulated: linear search

Algebraic law on the board:

(exists? p? '())          == ???
(exixts? p? '(cons a as)) == ???

          *** SLIDE ***
-> (define exists? (p? xs)
      (if (null? xs)
          (if (p? (car xs)) 
              (exists? p? (cdr xs)))))
-> (exists? pair? '(1 2 3))
-> (exists? pair? '(1 2 (3)))
-> (exists? ((curry =) 0) '(1 2 3))
-> (exists? ((curry =) 0) '(0 1 2 3))

13 February 2013: More higher-order functions

p2135655 p2135656 p2135657 p2135658

Quiz friday: satisfying assignments to Boolean formulas

List selection: filter

Problem: Give me a list of numbers; return only the even elements.

What are the laws?

(filter even? '())          == ???
(filter even? '(cons m ms)) == ???


          *** SLIDE ***
-> (define filter (p? xs)
     (if (null? xs)
       '()
       (if (p? (car xs))
         (cons (car xs) (filter p? (cdr xs)))
         (filter p? (cdr xs)))))
-> (filter (lambda (n) (>  n 0)) '(1 2 -3 -4 5 6))
(1 2 5 6)
-> (filter (lambda (n) (<= n 0)) '(1 2 -3 -4 5 6))
(-3 -4)
-> (filter ((curry <)  0) '(1 2 -3 -4 5 6))
(1 2 5 6)
-> (filter ((curry >=) 0) '(1 2 -3 -4 5 6))
(-3 -4)




          *** List filtering: composition revisited ***
-> (val positive? ((curry <) 0))
<procedure>
-> (filter positive?         '(1 2 -3 -4 5 6))
(1 2 5 6)
-> (filter (o not positive?) '(1 2 -3 -4 5 6))
(-3 -4)

"Lifting" functions to lists: map

Algorithm encapsulated: do this to every element

Problem: square every element of a list.

What are the laws?

(map square '())         ==
(map square (cons n ns)) ==

          *** SLIDE ***
-> (define map (f xs)
     (if (null? xs)
       '()
       (cons (f (car xs)) (map f (cdr xs)))))
-> (map number? '(3 a b (5 6)))
(#t #f #f #f)
-> (map ((curry *) 100) '(5 6 7))
(500 600 700)
-> (val square* ((curry map) (lambda (n) (* n n))))
<procedure>
-> (square* '(1 2 3 4 5))
(1 4 9 16 25)

The universal list function: fold

TeX slide TeX slide

Another view of operator folding:
TeX slide

foldr is a catamorphism

Another catamorphism: foldl associates to left

Homework retrospective and prospective (not presented in class)

How to handle

(take n xs)

What is the case analysis?

(take 0       '())         ==
(take 0       (cons z zs)) ==
(take (+ n 1) '())         ==
(take (+ n 1) (cons z zs)) ==

Proof about functions:

((flip f) x y) = (f y x)

(o flip flip)

15 February 2013: Tail calls and continuations - what to do next

p2155659 p2155660

Must get to solver today (before long weekend)

Tail calls

A call in tail position.

What is tail position?

Tail position is defined inductively:

Idea: the last thing that happens

Anything in tail position is the last thing executed!

Key idea is tail-call optimization!

Tail-call optimization:
TeX slide

Example of tail position:
TeX slide

Example of tail position:
TeX slide

Question: how much stack space is used by the call?

Another example of tail position:
TeX slide

Another example of tail position:
TeX slide

Question: how much stack space is used by the call?

Question: in your previous life, what did you call a construct that

  1. Transfers control to an arbitrary point in the code?
  2. Uses no stack space?

Continuations

Direct style - last action is to return a value

Continuation-passing style - last action is to "throw" value to a continuation

Simulate with a tail call.

How functions finish:
TeX slide

Motivating example: from existence to witness

Problem in interface design:
TeX slide

Ideas?

Bad choices:

Good choice:

Solution: new interface:
TeX slide

          *** Coding \lit{witness} with continuations ***
(define witness-cps (p? xs succ fail)
   (if (null? xs)
       (fail)
       (let ((x (car xs)))
         (if (p? x)
             (succ x)
             (witness-cps p? (cdr xs) succ fail)))))

Tail calls: continuations, recursion:
TeX slide

Question: how much stack space is used by the call?

Example use: instructor lookup:
TeX slide

          *** Simple continuations at work ***
-> (val 2012s '((Ramsey 105)(Hescott 170)(Chow 116)))
-> (instructor-info 'Ramsey 2012s)
(Ramsey teaches 105)
-> (instructor-info 'Chow 2012s)
(Chow teaches 116)
-> (instructor-info 'Souvaine 2012s)
(Souvaine is-not-on-the-list)

20 Feb 2013: Semantics and implementation of uScheme; full Scheme

p2205661 p2205662 p2205663

Plan for today:

  1. Analyze uScheme from the semantic point of view

  2. Pull back for slightly broader perspective on uScheme (end of part I)

  3. Part II: examples from your uScheme code and how to improve them; communicating higher aspirations for your code (maybe?)

New syntax, new environment, new semantics

First three of five questions: Syntax, values, environments

Key changes from Impcore

{ vs }:
TeX slide

{Evaluation judgment}:
TeX slide

{Evaluation rules}:
TeX slide

{Implementation of closures}:
TeX slide

{Applying closures}:
TeX slide

{Locations in closures}:
TeX slide

Closure optimizations

Lisp and Scheme retrospective

{ and the Five Questions}:
TeX slide

Common Lisp, Scheme:

Down sides:

Bottom line: it's all about lambda

Homework review

Many of you are doing much better on naming and contracts.

On the HOFs homework due Friday, failing grades for helper functions without contracts.

Homework review

Good, bad, and things to avoid

Mirror

          *** Classic mirror --- two case analyses ***
(define mirror (xs)   ; xs in LIST(SEXP)
 (if (null? xs)
   xs
   (if (atom? (car xs))   ; (car xs) in SEXP
     (append (mirror (cdr xs)) (list1 (car xs)))
     (append (mirror (cdr xs)) (list1 (mirror (car xs)))))))


          *** Improvement 1 --- no duplicate code ***
(define mirror (xs)   ; xs in LIST(SEXP)
 (if (null? xs)
   xs
   (append (mirror (cdr xs)) 
           (list1 (if (atom? (car xs))
                      (car xs)
                      (mirror (car xs))))))))
   ; 'if' has been pushed inside the call


          *** Improvement 2 --- $\mathit{LIST}(\mathit{SEXP}) \subset \mathit{SEXP}$ ***
(define mirror (xs)   ; xs in SEXP
 (if (atom? xs) ; just one case analysis
   xs
   (append (mirror (cdr xs))
           (list1 (mirror (car xs))))))


          *** Improvement 3 --- alternate case analysis ***
(define mirror (xs)   ; xs in SEXP
 (if (pair? xs) 
   (append (mirror (cdr xs))
           (list1 (mirror (car xs))))
   xs))


          *** Advanced version using HOFs ***
(define mirror (x)
  (if (atom? x)
    x
    (reverse (map mirror x))))

Flatten

          *** Flatten (excessive case analysis) ***
(define flatten (xs)
 (if (null? xs)
    xs
    (if (pair? (car xs)) ; <=== RED FLAG HERE
       (append (flatten (car xs)) (flatten (cdr xs)))
       (if (null? (car xs))
           (flatten (cdr xs))
           (append (list1(car xs)) (flatten (cdr xs)))))))


          *** Flatten equations --- complex form ***
(flatten '())           ==  '()
(flatten (cons xs ys))  ==  (append (flatten xs)
                                    (flatten ys))
(flatten (cons nonlist ys))  == ; hard to test for!
                      (cons nonlist (flatten ys))

; lasting lesson: general S-expressions harmful


          *** Flatten equations --- simple form ***
(flatten '())           ==  '()
(flatten atom)          ==  (list1 atom) ; non-nil
(flatten (cons v1 v2))  ==  (append (flatten v1)
                                    (flatten v2))




          *** Flatten (case analysis on xs only) ***
(define flatten (xs) ; xs in SEXP
                     ; return list of atoms in xs
 (if (null? xs)
   '()
   (if (pair? xs)
       (append (flatten (car xs)) (flatten (cdr xs)))
       (list1 xs))))


          *** Flatten (accumulating parameters) ***
(define flatten-append (xs ys)
               ; returns (append (flatten xs) ys)
  (if (pair? xs)
      (flatten-append (car xs)
                      (flatten-append (cdr xs) ys))
      (if (null? xs) ys
          (cons xs ys))))

(define flatten (xs)
  (flatten-append xs '()))

Length madness

          *** Red flag: testing \lit{length} for equality ***
(define mirror (xs)
 (if (atom? xs)   xs 
   (if (= 1 (length (cons (car xs) '()))) 
     (append (mirror (cdr xs))
             (cons (mirror (car xs)) '()))
     (cons (mirror (cdr xs))
           (mirror (cons (car xs) '()))))))


          *** Red flag eliminated ***
(define mirror (xs)
 (if (atom? xs)   xs 
   (append (mirror (cdr xs))
           (cons (mirror (car xs)) '()))

Avoidable allocations

          *** Name this predicate ***
  ; lists xs and ys in scope---what's happening?
  (if (equal? xs (take (length xs) ys))
      ...
      ...)


          *** Wait for it ***
...


          *** Specification of \lit{prefix?} predicate ***
(prefix? '()         '())          ==  #t
(prefix? '()         (cons y ys))  ==  #t
(prefix? (cons x xs) '())          ==  #f
(prefix? (cons x xs) (cons y ys))  ==  x = y 
                                   && (prefix? xs ys)


          *** Proper \lit{prefix?} predicate ***
(define prefix? (needle haystack)
  (if (null? needle)
    (if (null? haystack)
      (if (= (car needle) (car haystack))
        (prefix? (cdr needle) (cdr haystack))
;
; does not allocate and is quick to answer #f

Solecisms

bv - Largest element of a singleton list? (if (null? (cdr as)) (max* as) ...) ev

          *** Largest element of a singleton list? ***
    (if (null? (cdr as))
        (car as)
        ...)



          *** What's an empty list? ***
(if (= (length xs) 0) 
    ...
    ...
)


          *** What's an empty list? ***
(if (null? xs)
    ...
    ...
)


          *** Evil layout for if-expressions ***
(if  .......  ..............
     .......)


          *** Good layouts for if-expressions ***
(if  ....  .........   ........)

(if ....
    ..........
    .......)


          *** Some acceptable if-expressions ***
(if ..... 0
    ..........)

(if ..... '()
    ..........)


          *** Single-use \lit{lambda} ***
((lambda (xs) (rstack '() xs)) (car rest))


          *** Better ***
((lambda (xs) (rstack '() xs)) (car rest))

(let ((xs (car rest))) (rstack '() xs))


          *** Best ***
((lambda (xs) (rstack '() xs)) (car rest))

(let ((xs (car rest))) (rstack '() xs))

(rstack '() (car rest)))


          *** What's wrong here? ***
(define takewhile (p xs)
  (let*
    ((it (if (atom? xs)
             xs 
             (if (p (car xs))
                 (cons (car xs) (takewhile p (cdr xs))) 
                 (takewhile p (cdr xs))))))
    it))



          *** Fix it ***
(let* ((it e)) it) == e

(define takewhile (p xs)
   (if (atom? xs)
       xs 
       (if (p (car xs))
           (cons (car xs) (takewhile p (cdr xs))) 
           (takewhile p (cdr xs)))))

Bonus content: Scheme as it really is

  1. Macros!
  2. Cond expressions (solve nesting problem)
  3. Mutation
  4. Garbage collection
  5. Tail calls
  6. Applications and assessment

Macros!

A Scheme program is just another S-expression

Conditional expressions

          *** Real Scheme Conditionals ***
(cond (c1 e1)    ; if c1 then e1
      (c2 e2)    ; else if c2 then e2
       ...            ...
      (cn en))   ; else if cn then en

; Syntactic sugar---'if' is a macro:
(if e1 e2 e3) == (cond (e1 e2)
                       (#t e3))

Macros

Real Scheme: macros

A Scheme program is an S-expression

Mutation

Real Scheme: mutation

Not only variables can be mutated

Mutate heap-allocated cons cell:

(set-car! '(a b c) 'd)  => (d b c)

Circular lists, sharing, avoids allocation

21 Feb 2013: Introduction to ML

p2215664 p2215665 p2215666 p2215667 p2215668 p2215669 p2215670

Coming attractions

Apply your new knowledge in Standard ML:

Much less intellectual effort

Introduction to ML: programming with algebraic data types

New homework, and a different kind of effort:

Lectures on ML:

  1. Algebraic types and pattern matching
  2. A touch of types
  3. Everything else

Introduction

Meta: Not your typical introduction to a new language

ML Overview

Designed for programs, logic, symbolic data

Theme: talking about data

Board: ML = uScheme + pattern matching + exceptions + static types

Three new ideas:

  1. Pattern matching is big and important. You will like it.
  2. Exceptions are easy
  3. Static types get two to three weeks in their own right.

And lots of new concrete syntax!

Board: Let's do some examples

ML---The Five Questions

Syntax: expressions, definitions, patterns, types

Values: num/string/bool, record/tuple,

Environments: names stand for values (and types)

Evaluation: uScheme + case and pattern matching

Initial Basis: medium size; emphasizes lists

(Question Six: type system---a coming attraction)

A note about books

Ullman is easy to digest

Ullman is clueless about good style

Suggestion:

(My style is not flawless---some Haskell style has crept in---but it will serve you better than Ullman. And I've made some effort at consistency.)

Algebraic data types

Tidbits:

Defining algebraic types

Board:

Exegesis (on board):

22 February 2013: Learning and exploiting the ML type system

p2225671 p2225672 p2225673 p2225674 p2225675 p2225676 p2225677 p2225678

Background for datatype review (board):

This is all you need to know about the special built-in type constructors (cross and arrow).

Algebraic datatype review:

Frequently overlooked

An algebraic data type is a collection of alternatives

Don't forget:

The thing named is the value constructor

(Also called "datatype constructor")

          *** SLIDE ***
datatype bool     = true | false  (* copy me NOT! *)

datatype 'a list  = nil           (* copy me NOT! *)
                  | op :: of 'a * 'a list

datatype 'a heap  = EHEAP
                  | HEAP of 'a * 'a heap * 'a heap

type bool          val true  : bool
type 'a list       val false : bool
type 'a heap       val nil   : forall 'a . 'a list
                   val op :: : forall 'a . 
                            'a * 'a list -> 'a list
val EHEAP : forall 'a . 'a * 'a heap * 'a heap -> 'a heap
val HEAP  : forall 'a .                           'a heap

Exegesis (on board):

Language support for algebraic types

Eliminate values of algebraic types

New language construct case (an expression)

fun length xs =
  case xs
    of []      => 0
     | (x::xs) => 1 + length xs

At top level, better than

When possible, write

fun length []      = 0
  | length (x::xs) = 1 + length xs

"Syntactic sugar"

Talking type theory: Introduction and elimination constructs

Part of learning any new field: talk to people in their native vocabulary

It's like knowing what to say when somebody sneezes.

Types and their uses:
Type Produce Consume
Introduce Eliminate
arrow Lambda (fn) Application
algebraic Apply constructor Pattern match
tuple (e1, ..., en) Pattern match!

Example pattern match on a tuple:

val (left, pivot, right) = split xs

Making types work for you

The types survey:

Baffling         Noise I can ignore          Information I understand

Today, add to far right: type help me program

Types help me, part I: type-directed programming

Common idea in functional programming: "lifting:

val lift : forall 'a . ('a -> bool) -> ('a list -> bool)

do the example

25 Feb 2013: Making types work for you; more ML

p2255679 p2255680 p2255681

Quiz question:
TeX slide

Wait for it ...

          *** Quiz answers ***
datatype sx1 = ATOM1 of atom
             | LIST1 of sx1 list

datatype sx2 = ATOM2 of atom
             | PAIR2 of sx2 * sx2

Plan for today:

  1. Finish the lift example (slide for context)

     val lift : forall 'a . ('a -> bool) -> ('a list -> bool)
  2. The people's choice:

    • Another type-directed example (heap insertion)

    • ML traps and pitfalls

    • ML from 10,000 feet

Types and their ML constructs:
TeX slide

          *** Type-directed coding (review) ***
val lift : ('a -> bool) -> ('a list -> bool)
fun lift p = (fn xs => (case xs
                          of [] => false
                           | z::zs => p z orelse
                                      lift p zs))


          *** Merge top-level \lit{fn} into \lit{fun} ***
fun lift p xs = case xs of []    => false
                         | z::zs => p z orelse
                                    lift p zs


          *** Merge top-level \lit{case} into \lit{fun} ***
fun lift p []      = false
  | lift p (z::zs) = p z orelse lift p zs


          *** I know this function! ***
fun exists p []      = false
  | exists p (z::zs) = p z orelse exists p zs

Heap insertion (optional)

          *** Heap insertion ***
datatype 'a heap  = EHEAP
                  | HEAP of 'a * 'a heap * 'a heap

val insert : int * int heap -> int heap

Alert! Balance invariant...

ML traps and pitfalls

ML Traps and pitfalls:
TeX slide

Integer literals as patterns, overlapping patterns

          *** Order of clauses matters ***
fun take n (x::xs) = x :: take (n-1) xs
  | take 0 xs      = []
  | take n []      = []

(* what goes wrong? *)

Gotcha - Value polymorphism:
TeX slide

          *** Gotcha --- overloading ***
- fun plus x y = x + y;
> val plus = fn : int -> int -> int
- fun plus x y = y + y : real;
> val plus = fn : real -> real -> real

Gotcha --- equality types:
TeX slide

Gotcha --- parentheses

Put parentheses around anything with |

case, handle, fn

Function application has higher precedence than any infix operator

Gotcha --- fixity

Fixity:

infixr 5 @ (* associativity, precedence *)

Revert using op

          *** Lists and fixity ***
- [+, -, *, div];
! Toplevel input:
! [+, -, *, div];
!  ^
! Ill-formed infix expression
- [op +, op -, op *, op div];
> val it = [fn, fn, fn, fn] : (int * int -> int) list
- length it;
> val it = 4 : int
- 

Bonus content (seen in examples)

Syntactic sugar for lists

          *** Syntactic sugar for lists ***
- 1 :: 2 :: 3 :: 4 :: nil; (* :: associates to the right *)
> val it = [1, 2, 3, 4] : int list

- "the" :: "ML" :: "follies" :: [];
> val it = ["the", "ML", "follies"] : string list

> concat it;
val it = "theMLfollies" : string

Bonus content not covered in class: More type-directed programming

Another example:

val map: forall 'a, 'b . ('a -> 'b) -> ('a list -> 'b list)

Do map on the board

Use fun syntax for Currying

          *** Code for a function consuming lists ***
fun map f []      = []
  | map f (x::xs) = f x :: map f xs

(*  FUNCTION APPLICATION HAS HIGHER
    PRECEDENCE THAN ANY INFIX OPERATOR! *)

More examples:

Option.map
filter
flatten (with sx1)
curry     flip       infixr 0 $       
uncurry   fst
          snd

Running ML

Bonus: running ML

To run Moscow ML:

ledit mosml -P full

And tell it:

help "";
use "warmup.sml";

Also /usr/bin/sml, /usr/bin/mlton

Bonus content not covered in class: ML from 10,000 feet

ML from 10,000 feet:
TeX slide

Environments

The value environment

Names bound to immutable values

(Immutable ref and array values point to mutable locations

ML has no binding-changing assignment

Definitions add new bindings (hide old ones):

val pattern = exp
val rec pattern = exp
fun ident patterns = exp
datatype ... = ...

Nesting environments

At top level, definitions

Definitions contain expressions:

def ::= val pattern = exp

Expressions contain definitions:

exp ::= let defs in exp end

Sequence of defs has let-star semantics

Patterns

What is a pattern?

pattern ::= variable
          | wildcard
          | value-constructor [pattern]
          | tuple-pattern
          | record-pattern
          | integer-literal
          | list-pattern

Design bug: no lexical distinction between

Workaround: programming convention

Functions

Function pecularities: 1 argument

Each function takes 1 argument, returns 1 result

For "multiple arguments," use tuples!

 fun factorial n =
   let fun f (i, prod) = 
         if i > n then prod else f (i+1, i*prod)
   in  f (1, 1)
   end

 fun factorial n =  (* you can also Curry *)
   let fun f i prod = 
         if i > n then prod else f (i+1) (i*prod)
   in  f 1 1
   end

Tuples are "usual and customary."

Mutual recursion:
TeX slide

Types

Syntax of ML types:
TeX slide

Syntax of ML types:
TeX slide

Polymorphic types:
TeX slide

Old and new friends:
TeX slide

Exceptions

Board:

Syntax:

Semantics:

Bonus content: more programming examples

          *** SLIDE ***
val filter : forall 'a . ('a -> bool) ->
                         'a list -> 'a list
fun filter p []      = []
  | filter p (x::xs) =
       case p x
         of true  => x :: filter p xs
          | false =>      filter p xs

fun filter p []      = []  
  | filter p (x::xs) =
       if p x then x :: filter p xs
              else      filter p xs

Flattening S-expressions

Let's not care what an atom is

datatype 'a sxl = SXLEAF of 'a
                | SXLIST of 'a sxl list

Exercise --- write

val flatten : forall 'a . 'a sxl -> 'a list


          *** SLIDE ***
fun flatten (SXLEAF a)  = [a]
  | flatten (SXLIST ts) = (List.concat o map flatten) ts

fun flatten (SXLEAF a)  = [a]
  | flatten (SXLIST ts) = List.concat (map flatten ts)

fun flatten t =
  let fun flatapp (SXLEAF a,  tail) = a :: tail
        | flatapp (SXLIST ts, tail) =
             foldr flatapp tail ts
  in  flatapp (t, [])
  end

27 Feb 2013: Type systems

p2275682 p2275683 p2275684 p2275685 p2275686 p2275687 p2275688 p2275689

Announcements

The midterm exam:

Preparing for the midterm review on Monday (Followup March 15)

Type systems

What kind of value do we have?

 n + 1

 "hello" ^ "world"

 (fn n => n * (n - 1))

 if p then 1 else 0

 if true then 1 else 0

Questions type systems can answer:

Source of new language ideas for next 20 years

Needed if you want to understand advanced designs (or create your own)

Type system and checker for a simple language

Q: What context do we need to evaluate an expression?

Q: Do we need all the same context to decide on a type?

Q: What do we need then?

Define a datatype for expressions with

Language of expressions

Numbers and Booleans:

datatype exp = ARITH of arithop * exp * exp
             | CMP   of relop   * exp * exp
             | IF    of exp * exp * exp
             | LIT   of int
and      arithop = PLUS | MINUS | TIMES | ...
and      relop   = EQ | NE | LT | LE | GT | GE

datatype ty = INTTY | BOOLTY

What's the type of an expression?

What is a type?

1 March 2013: Implementing a type checker

p3015690 p3015691 p3015692

Where have we been?

Where are we going?

This is a big chunk of what language designers do.

Arithmetic expressions, recapitulated

Board: rules developed for ARITH, CMP, LIT

Board: placeholder for IF

(Show syntax on slide)

Language of expressions

Numbers and Booleans:

datatype exp = ARITH of arithop * exp * exp
             | CMP   of relop   * exp * exp
             | IF    of exp * exp * exp
             | LIT   of int
and      arithop = PLUS | MINUS | TIMES | ...
and      relop   = EQ | NE | LT | LE | GT | GE

datatype ty = INTTY | BOOLTY

Develop rule for IF

Write the code

An implementor's trick: If you see identical types in a rule,

Contexts and term variables

Add variables and let binding to our language, what happens?

Ideas:

4 March 2013: Midterm review

What to expect on the exam:

Notes from the homework:

8 March 2013: Monomorphic type checking

p3085693 p3085694 p3085695 p3085696 p3085697 p3085698 p3085699 p3085700

Where we've been and where we're going

New watershed in the homework

What's next is much more sophisticated type systems, with an infinite number of types. We'll focus on two questions:

We'll look at these questions in two contexts: monomorphic and polymorphic languages.

(Note on deadlines: I'm trying to get you done with type checking before break. Open to change provided it is fair to those with travel plans.)

Design and implementation of monomorphic languages

Here's how it works:

  1. Every new variety of type requires special syntax

  2. We get three kinds of typing rules

  3. Implementation is a straightforward application of what you already know.

Language designer's agenda:

Type formation

Examples: well-formed types

These are types:

Board: little language of types

Examples: not yet types, or not types at all

These "types in waiting" don't classify any terms

These are utter nonsense

Type constructors

Technical name for "types in waiting"

Zero or more args, produce type

More complex type constructors:

What's a good type?:
TeX slide

Type judgments for monomorphic system

Two judgments

Monomorphic type rules

Type rules for variables:
TeX slide

Notice: one rule for if!! (and while)

Type rules for control:
TeX slide

Classic types for data structures

Product types: both x and y:
TeX slide

Pair rules generalize to product types with many elements (tuples,''structs,'' ``records'')

Arrow types: function from x to y:
TeX slide

Typical syntactic support for types

Explicit types on lambda and define:

Abstract syntax:

datatype exp = ...
 | LAMBDA of (name * tyex) list * exp
    ...
datatype def = ...
 | DEFINE of name * tyex * ((name * tyex) list * exp)
    ...

Array types: array of x:
TeX slide

Board: rules for C/C++ pointer types?

Coding the arrow-introduction rule

TeX slide

Board: Lambda rule

          *** Type-checking LAMBDA ***
datatype exp = LAMBDA of (name * tyex) list * exp 
   ...
fun ty (LAMBDA (formals, body)) = 
  let val Gamma' = (* body gets new env *)
        foldl (fn ((n, ty), g) => bind (n, ty, g))
              Gamma formals
      val bodytype = typeof (body, Gamma')
      val formaltypes = 
        map (fn (n, ty) => ty) formals
  in  funtype (formaltypes, bodytype)
  end

11 March 2013: Polymorphic type checking

Agenda for today:

Type formation: composing types

Typed Impcore:

Standard ML:

Board: type-formation ideas

Representing type constructors generically:
TeX slide

Type formation through kinds

Type formation through kinds:
TeX slide

Use kinds to give arities:
TeX slide

The kinding judgment:
TeX slide

Kinding rules for types:
TeX slide

Limitations of monomorphic type systems

Monomorphic types are limiting

Each new type constructor requires

Monomorphic burden: Array types:
TeX slide

Notes:

Monomorphism hurts programmers too

Users can't create new syntax

User-defined functions are monomorphic:

(define int lengthI ((list int) l)
   (if (null? l) 0 (+ 1 (lengthI (cdr l)))))
(define int lengthB ((list bool) l)
   (if (null? l) 0 (+ 1 (lengthB (cdr l)))))
(define int lengthS ((list sym) l)
   (if (null? l) 0 (+ 1 (lengthS (cdr l)))))

Next week: polymorphism!

Quantified types

Quantified types:
TeX slide

Representing quantified types

Two new alternatives for tyex:

datatype tyex
  = TYCON  of name
  | CONAPP of tyex * tyex list 
  | FORALL of name list * tyex
  | TYVAR  of name

Kinding rules for quantified types:
TeX slide

          *** Substitute for quantified variables ***
-> length
<proc> : (forall ('a) (function ((list 'a)) int))
-> (@ length int)
<proc> : (function ((list int)) int)
-> (length '(1 2 3))
type error: function is polymorphic; instantiate before applying
-> ((@ length int) '(1 2 3))
3 : int


          *** Substitute what you like ***
-> length
<proc> : (forall ('a) (function ((list 'a)) int))
-> (@ length bool)
<proc> : (function ((list bool)) int)
-> ((@ length bool) '(#t #f))
2 : int


          *** More "Instantiations" ***
-> (val length-int (@ length int))
length-int : (function ((list int)) int)
-> (val cons-bool (@ cons bool))
cons-bool : (function (bool (list bool)) 
                                (list bool))
-> (val cdr-sym (@ cdr sym))
cdr-sym : (function ((list sym)) (list sym))
-> (val empty-int (@ '() int))
() : (list int)

Bonus instantiation:

-> map
<proc> : 
  (forall ('a 'b) 
      (function ((function ('a) 'b) 
                 (list 'a)) 
           (list 'b)))
-> (@ map int bool)
<proc> : (function ((function (int) bool) 
                    (list int)) 
              (list bool))

Create your own!

Abstract over unknown type using type-lambda

  -> (val id (type-lambda ('a)
                (lambda (('a x)) x)))
  id : (forall ('a) (function ('a) 'a))

'a is type parameter (an unknown type)

This feature is parametric polymorphism

Board: two forms of abstraction:

term type
lambda function (arrow)
type-lambda forall

Power comes at notational cost

Function composition

-> (val o (type-lambda ('a 'b 'c) 
     (lambda (((function ('b) 'c) f)
              ((function ('a) 'b) g))
        (lambda (('a x)) (f (g x))))))
o : (forall ('a 'b 'c) 
       (function ((function ('b) 'c) 
                  (function ('a) 'b)) 
           (function ('a) 'c)))

Aka o :

Type rules for polymorphism

Instantiate by substitution:
TeX slide

Generalize with type-lambda:
TeX slide

13 March 2013: Polymorphism wrapup; thinking about type inference

p3135701 p3135702 p3135703 p3135704 p3135705 p3135706 p3135707 p3135708 p3135709 p3135710

Instantiate by substitution:
TeX slide

Generalize with type-lambda:
TeX slide

          *** A phase distinction embodied in code ***
fun checkThenEval (d, (delta, gamma, rho)) =
  let val (gamma', tystring)  = elabdef (d, gamma, delta)
      val (rho',   valstring) = evaldef (d, rho)
      val _ = print (valstring ^ " : " ^ tystring)
  in  (delta, gamma', rho')
  end

Three environments --- what happens?:
TeX slide

Three environments revealed:
TeX slide

Board exercise: term, type, value

Q: What predicts the set of values? The syntax? The type?

Q: If you see a lambda, what do you know about the value?

Q: If you see a literal, what do you know about the value?

Q: If you see an application, what do you know about the value?

15 March 2013: Type inference

p3155711 p3155712 p3155713 p3155714 p3155715 p3155716 p3155717 p3155718 p3155719 p3155720 p3155721 p3155722 p3155723 p3155724 p3155725 p3155726

Midterm evaluation note: clear that ML Syntax is something you would like improved. But the CELT people are not technical, and they were not able to articulate what sort of improvement you are looking for. If you can say something on Piazza, anonymously or otherwise, that would help us.

(Other midterm evaluation stuff: after break we will take a fresh look at TA things and at study groups, as well as other issues.)

ML type inference

One sophisticated idea: use fresh variable for unknown types; hold knowledge in constraints

New topic: Type inference:
TeX slide

          *** What type inference accomplishes ***
-> (define     double (x)       (+ x x))
double                         ;; uScheme
-> (define int double ((int x)) (+ x x))
double : (function (int) int)  ;; Typed uSch.
-> (define     double (x)       (+ x x))
double : int -> int            ;; uML




          *** What else type inference accomplishes ***
-> ((@ cons bool) #t ((@ cons bool) #f (@ '() bool)))
(#t #f) : (list bool)    ;; typed uScheme
-> (   cons       #t (   cons       #f    '()      ))
(#t #f) : bool list      ;; uML

Key ideas:

  1. For each unknown type, introduce a fresh type variable

  2. Enforce equality constraints

  3. Introduce type-lambda at let/val bindings

N.B. Book is "constraints first;" lecture will be "type system first." Use whatever way works for you.

Let's do an example on the board

(val-rec double (lambda (x) (+ x x)))

What do we know?

Key idea: record the constraint in a typing judgement

a2 = int /\ a2 = int, { double : a1, x : a2 } |- (+ x x) : int

Example: if

Example:

Inferring polymorphic types

Examples for board:

let val app2 = (lambda (f x y)
                  (begin
                    (f x)
                    (f y)))

let val cc = (lambda (nss) (car (car nss)))

What you know and can do after this lecture

After this lecture, you can write type inference for everything except the let forms. Your type inference can return a type and a constraint.

In place of solve, write a function that prints the constraint to be solved, then returns the identity substitution idsubst.

25 March 2013: Hindley-Milner types; solving constraints

p3255727 p3255728 p3255729 p3255730 p3255731

Forall things

managing quantified types
val and val-rec let, letrec, ... lambda
FORALL contains all variables (because none are free in the context) FORALL contains variables not free in the context FORALL is empty
Generalize over all variables (because none are free in the context) Generalize over variables not free in the context Never generalize

Sad news: full type inference for polymorphism is not decidable.

Solution: parameters have monomorphic types

          *** Hindley-Milner types ***
datatype ty
  = TYCON  of name        
  | CONAPP of ty * ty list
  | TYVAR  of name        

datatype type_scheme
  = FORALL of name list * ty

Key ideas:
TeX slide

Key ideas repeated:
TeX slide

{Type inference}:
TeX slide

{Type inference, operationally}:
TeX slide

Writing the constraint solver

          *** Solve these constraints! ***
datatype con = =*= of ty  * ty
             | /\  of con * con
             | TRIVIAL
infix 4 =*=
infix 3 /\

Q: What constitutes a solution?

A: A standard form (if you missed this class, it's in the book)

Board: which of these have solutions?

'a =*= int
'a =*= int list
'a =*= int -> int
'a =*= 'a
'a =*= tau        (arbitrary tau)

Board: which of these have solutions?

int =*= bool
int list =*= bool list

Board: which of these have solutions?

'a * int =*= bool * 'b
'a * int =*= bool -> 'b

Question: in solving tau1 =*= tau2, how many potential cases are there to considerer?

Question: which of these cases are interesting?

Question: how are you going to handle each case?

Now let's see what rules we have applied:

Some constraint-rewriting rules:
TeX slide

What you know and can do after this lecture

After this lecture, you can write a function which, given a constraint C, has one of three outcomes:

The last case is the interesting one; on Wednesday we will see how to put such a constraint into standard form, making a complete constraint solver.

27 March 2013: Standard form; Milner's LET; generalization

p3275732 p3275733 p3275734 p3275735 p3275736 p3275737 p3275738 p3275739 p3275740 p3275741

Exam grades

Points Grade
50+ Excellent
37-49 Very Good
25-36 Good
15-24 Fair
<15 Poor

Below 20 is cause for concern

All theory or all practice is cause for concern (e.g., 20 or more theory but single-digit practice)

Return to constraint solving

What you already know:

Now let's see an interesting case where something goes wrong:

'a * int =*= bool * 'a    

is equivalent to

'a =*= bool /\ int =*= 'a

is equivalent to

'a =*= bool /\ 'a =*= int

But this is not solvable!

Enter standard form:

Key rules for conjunction:
TeX slide

Another non-standard form:

'a =*= 'b list /\ 'b =*= 'a list

Another non-standard form (composed of two standard forms)

'a =*= 'b list /\ 'b =*= int

(order of substitution matters)

Trap for the unwary:
TeX slide

Another trap for the unwary:
TeX slide

Problem 13: you can get to

'a =*= tau /\ C

easily enough. How do you get from there to a standard form?

Try

'a =*= 'c /\ ('b =*= 'c /\ 'b =*= int)

Conjunct

'a =*= 'c 

is in standard form already. Substituting 'c for 'a on the right leaves unchanged.

Conjunct

 'b =*= 'c /\ 'b =*= int
~= (swap /\)   
 'b =*= int /\ 'b =*= 'c
~= (substitute)   
 'b =*= int /\ int =*= 'c
~= (swap =*=, congruence)   
 'b =*= int /\ 'c =*= int

is now a standard form.

So the original, by congruence, is equivalent to

'a =*= 'c /\ 'b =*= int /\ 'c =*= int

Is it a standard form?

29 March 2013: Milner's LET

Forall things

managing quantified types
val and val-rec let, letrec, ... lambda
FORALL contains all variables (because none are free in the context) FORALL contains variables not free in the context FORALL is empty
Generalize over all variables (because none are free in the context) Generalize over variables not free in the context Never generalize

Examples:

(lambda (ys)
   (let ((s (lambda (x) (cons x '()))))
      (pair (s 1) (s #t))))

(lambda (ys)
   (let ((extend (lambda (x) (cons x ys))))
      (pair (extend 1) (extend #t))))

(lambda (ys)
   (let ((extend (lambda (x) (cons x ys))))
      (extend 1)))

Generalization:
TeX slide

Milner's :
TeX slide

Let with constraints:
TeX slide

Let with constraints, operationally:

  1. typesof: returns tau_1, ..., \tau_n and C_combined

  2. split (C_combined, freetyvarsGamma Gamma) returns C, C-prime

  3. val theta = solve C'

  4. consubst, freetyvarsGamma, union

  5. Map anonymous lambda using generalize, get all the sigma_i

  6. Extend the typing environment Gamma

  7. Recursive call to type checker, gets C_b,

  8. Return (tau, consubst theta C /\ C_b)

1 April 2013: Lambda calculus

Where have we been and where are we going?

The world's simplest reasonable programming language

Only three syntactic forms:

M ::= x | \x.M | M M'

Everything is programming with functions

First example:

(\x.\y.x) M N --> (\y.M) N --> M

Crucial: argument N is never evaluated (could have an infinite loop)

Programming with lambda calculus

Alert to the reading: Wikipedia is reasonably good on this topic

TA sessions on this topic (when? two days this week)

Everything is continuation-passing style

Q: Who remembers the boolean equation solver?

Q: What classes of results could it produce?

Q: How were the results delivered?

Q: How shall we do Booleans

Booleans take two continuations:

true  = \x.\y.x
false = \x.\y.y

if M then N else P = ???

Let's do pairs!

Coding lists

3 April 2013: Church numerals; semantics of lambda calculus

Board: Wikipedia good: "Church numerals"

Coding numbers

Encoding natural numbers:
TeX slide

Church Numerals:
TeX slide

          *** Church Numerals to machine integers ***
; uscheme or possibly uhaskell
-> (define to-int (n)
          ((n ((curry +) 1)) 0))
-> (to-int three)
3
-> (to-int ((times three) four))
12



          *** Church Numerals in $\lambda$ ***
zero  = \f.\x.x;
succ  = \n.\f.\x.f (n f x);
plus  = \n.\m.n succ m;
times = \n.\m.n (plus m) zero;
 ...
-> four;
\f.\x.f (f (f (f x)))
-> three;
\f.\x.f (f (f x))
-> times four three;
\f.\x.f (f (f (f (f (f (f (f (f (f (f (f x)))))))))))

Question: What's missing from this picture?

Answer: We're missing recursive functions.

Astonishing fact: we don't need letrec or val-rec (Friday)

Beta reduction, normal form, reduction strategies

Operational semantics of lambda calculus

New kind of semantics: small-step

New judgment form

M --> N   ("M reduces to N in one step")

No context!! No turnstile!!

Just pushing terms around == calculus

{Reduction rules}:
TeX slide

Board examples:

  1. Are these functions the same?

     \x.\y.x
     \w.\z.w
  2. Are these functions the same?

     \x.\y.z
     \w.\z.z

Free variables:
TeX slide

Examples of free variables:

\x . + x y

\x. \y. x

Beta-reduction

The substitution in the beta rule is the heart of the lambda calculus

Capture-avoiding substitution:
TeX slide

Example:

(\yes.\no.yes)(\time.no) ->
\z.\time.no

and never

\no.\time.no    // WRONG!!!!!!

5 April 2013: Normal forms and reduction strategies

Board: beta rule, structural rules

Review:

(\yes.\no.yes) (\time.no) tuesday
   ->   WRONG!!!
(\no.\time.no) tuesday
   ->
\time.tuesday

Must rename the bound variable:

(\yes.\no.yes) (\time.no) tuesday
   ->   
(\yes.\z.yes)  (\time.no) tuesday
   ->  
(\z.\time.no)  tuesday
   ->
\time.no

Capture-avoiding substitution:
TeX slide

{Renaming of bound variables}:
TeX slide

Conversion and reduction:
TeX slide

Nondeterminism of conversion:

               A
              / \
             V   V
            B     C

Now what??

Church-Rosser Theorem:
TeX slide

Normal forms

Idea: normal form

A term is a normal form if

It cannot be reduced

What do you suppose it means to say

Idea: normal form

A term is a normal form if

It cannot be reduced

A term has a normal form if

There exists a sequence of reductions that terminates (in a normal form)

A term has no normal form if

It always reduces forever
(This term diverges)

Normal forms code for values:
TeX slide

Reduction strategies (your homework, part 1)

Applicative-order reduction

Given a beta-redex

(\x.M) N

do the beta-reduction only if N is in normal form

Q: Does applicative order ever prevent you from making progress?

A: No. We can prove it by induction on the number of lambdas in N

Normal-order reduction:
TeX slide

Normal-order reduction

Always choose leftmost, outermost redex

"Normal-order" stands for produces a normal form, not for "the normal way of doing things"

Normal-order illustration:
TeX slide

Not your typical call-by-value semantics!

Fixed points, recursion

What solves this equation?:
TeX slide

8 April 2013: Fixed points, recursion, calculus

Review:
TeX slide

Quiz questions

Is there a solution? Is it unique? If so, what is it?

f1 = \n.\m.(eq? n m) n 
              (plus n (f1 (succ n) m));

f2 = \n.f2 (isZero? n 100 (pred n));

f3 = \xs.xs nil (\z.\zs.cons 0 (f3 zs));

f4 = \xs.\ys.f4 ys xs;

Wait for it...:
TeX slide

Quiz answers

f1 = \n.\m.(eq? n m) n 
              (plus n (f1 (succ n) m));
    ; sigma (sum from n to m)

f2 = \n.f2 (isZero? n 100 (pred n));
    ; no unique solution (any constant f2)

f3 = \xs.xs nil (\z.\zs.cons 0 (f3 zs));
    ; map (const 0)

f4 = \xs.\ys. f4 xs ys;
    ; not unique: constant functions, commutative ops

Recursion = Fixed point:
TeX slide

Suppose g F = F. Proof that F is factorial.

For all n, g F n = n!, by induction:

F 0 = g F 0 = 1
F n
  = { by assumption }
g F n 
  = { definition of g }
if n = 0 then 1 else n * F (n-1)
  = { assumption, n > 0 }
n * F (n-1)
  = { induction hypothesis }
n * (n-1)!
  = { definitiion of factorial }
n!

Now you do it

          *** Conversion to fixed point ***

length = \xs.null? xs 0 (+ 1 (length (cdr xs)))


lg = \lf.\xs.null? xs 0 (+ 1 (lf (cdr xs)))

One startling idea

You can define a fixed-point operator

Fixed-point operators

A simple algebraic law

If

    fix g = g (fix g)

then fix g can define recursive functions!

The only recursion equation you'll ever need

{Y combinator can implement }:
TeX slide

Lambda calculus in context

What's its role in the world of theory?

Operational semantics          Type theory     Denotational      Lambda 
(Natural deducation style)                       semantics      calculus
--------------------------     -----------     ------------     --------

Interpreters like Python       type checkers   compilers        *models*

Why is it "calculus"?

What's the role of calculi in computer science:

Why so many calculi? They have simple metatheory and proof technique.

10 April 2013: Object-orientation and Smalltalk

Preliminaries

Where have we been?

What kind of code have we been looking at?

What about big programs?

An area of agreement and a great divide:

                      INFORMATION HIDING
                          /         \
                         /           \
                  reuse /             \ modular reasoning
                       /               \
                      /                 \
                   OBJECTS            MODULES

Two kinds of reuse:

Don't conflate them!

History of objects

We know that mixing code and data can create powerful abstractions (function closures)

Objects are another way to mix code and data

Pioneers were Nygaard and Dahl, who added objects to Algol 60, producing SIMULA-67, the first object-oriented language

What's an object?

Agglutination containing

A lot like a closure

What are objects good at?

Not really useful for building small things

If you build a big, full-featured abstraction, you can easily use inheritance to build another, similar abstraction. Very good at adding new kinds of things that behave similarly to existing things.

For your homework, you'll take a Smalltalk system that has three kinds of numbers, and you'll add a fourth kind of number.

What's hard about objects?

If you do anything at all interesting, your control flow becomes smeared out over half a dozen classes, and your algorithms are nearly impossible to undrstand.

Smalltalk

Why Smalltalk?

The five questions:

Impcore syntax:
TeX slide

Smalltalk syntax:
TeX slide

Smalltalk syntax:
TeX slide

Message passing

Look at SEND

N.B. BLOCK and LITERAL are special objects.

12 April 2013: Smalltalk protocols and hierarchies

Protocol --- the interface to an object

Protocol is Smalltalk term of art:

Ruby dialect "duck typing" is a statement about protocols

Protocol is determined by the class of which an object is an instance

SLIDE on Object protocol is not printing :-(

TeX slide

Arities:

Every object gets not just the protocol but the implementations from its class. And a class can inherit from its superclass (more undefined terms) all the way up to class Object.

          *** Simple examples ***
-> true
<True>
-> True
<class True>
-> Object
<class Object>
-> (isNil 3)
<False>
-> (isNil nil)
<True>
-> (println nil)
nil
nil

Smalltalk's initial basis

Blocks and Booleans

Blocks are closures

Blocks are objects

Booleans use continuation-passing style

Protocol for Booleans:
TeX slide

Booleans implemented with two classes True and False

Classes True and False:
TeX slide

Method dispatch in the Booleans

Protocol for Booleans:
TeX slide

Classes True and False:
TeX slide

Board - Method dispatch

To answer a message:

  1. Consider the class of the receiver

  2. Is the method with that name defined?

  3. If so, use it

  4. If not, repeat with the superclass

Run out of superclasses?

"Message not understood"

{ message dispatched to class }:
TeX slide

Blocks, control flow, the block protocol

          *** Blocks manage loops ***
-> (val x 10)
-> (val y 20)
-> (whileTrue: [(<= x (* 10 y))]
      [(set x (* x 3))])
nil
-> x
270

Protocol for blocks:
TeX slide

17 April 2013: Collections; subtyping; inheritance; double dispatch

Things to look for in Smalltalk

Today:

  1. Wide interfaces, reused

  2. Algorithms smeared out over multiple classes

  3. Behavioral subtyping, aka "Duck typing"

  4. Old wine in new bottles

    • Exceptions

    • Higher-order methods

    • Polymorphic methods

  5. Initialization

  6. Double dispatch

Collections

Goal of objects is reuse

Key to successful reuse is a well-designed class hierarchy

``Collection hierarchy'':
TeX slide

Collection contain things
Set objects in no particular order
KeyedCollection objects accessible by keys
Dictionary any key
SequenceableCollection keys are consecutive integers
List can grow and shrink
Array fixed size, fast access

Collection mutators:
TeX slide

Collection observers:
TeX slide

Collection iterators:
TeX slide

Implementing Collections

Implementing collections:
TeX slide

Reusable methods:
TeX slide

Question: what's the most efficient way to find the size of a list?

Question: what's the most efficient way to find the size of an array?

{ method}:
TeX slide

Subtyping

Key strategy for reuse in object-oriented languages: subtype polymorphism

Subtyping mathematically:
TeX slide

Subtyping is not inheritance:
TeX slide

{The four crucial {} methods}:
TeX slide

Example collection - Sets

TeX slide

Most subclass methods work by delegating all or part of work to list members

N.B. Set is a client of List, not a subclass!

Next example highlight: class method and super!

TeX slide

Metaclasses

                                             Object!
                                               /
                                              /
                                           Class
                                            /
                                           /
                        Object ===> Object's metaclass
                          /              /
                         /              /
                   Collection ===> Collection's metaclass
                       /              /
                      /              /
     students ====> Set ========> Set's metaclass
                    /              /
                   /              /
 alphanum ====> CharSet ====> CharSet's metaclass

Double Dispatch

Typical object-orientation:

What if you need to choose code based on both receiver and argument?

Solution: method name encodes both operation and type of argument

Examples:

addIntegerTo:
addFloatTo:

22 April 2013: Information hiding using modules

Review: Information hiding using objects

Smalltalk

(Other object-oriented languages have elaborate controls for public/private)

Information hiding, really?

Problem: inheritance violates abstraction and modularity

Modules and separate compilation

Why modules?

Unlocking the final door for building large software systems

Many paths will be open to you:

Modules overview

Functions of a true modules system:

Real modules include separately compilable interfaces and implementations

Interfaces

Collect declarations

Things typically declared:

Terminology: a module is a client of the interfaces it depends on

Roles of interfaces in programming:

The best-proven technology for structuring large systems.

Ways of thinking about interfaces

Two approaches to writing interfaces

Interface "projected" from implementation:

Full interfaces:

Structure of implementations

Standard ML Modules

The Perl of module languages?

What we've been using so far is the core language

Modules are a separate language layered on top.

ML module terminology

Interface is a signature

Implementation is a structure

Generic module (parameterized implementation) is a functor

Structures and functors match signatures

Signature basics

Signature says what's in a structure

Specify types (w/kind), values (w/type), exceptions.

Ordinary type examples:

    type t        // abstract type, kind *
    eqtype t
    type t = ...  // 'manifest' type
    datatype t = ...

Type constructors work too

    type 'a t     // abstract, kind * => *   
    eqtype 'a t
    type 'a t = ...
    datatype 'a t = ...

ML Modules examples, part I

          *** Signature example: Integers ***
signature INTEGER = sig
  eqtype int             (* <-- ABSTRACT type *)
  val ~   : int -> int
  val +   : int * int -> int
  val -   : int * int -> int
  val *   : int * int -> int
  val div : int * int -> int
  val mod : int * int -> int
  val >   : int * int -> bool
  val >=  : int * int -> bool
  val <   : int * int -> bool
  val <=  : int * int -> bool
  val compare : int * int -> order
  val toString   : int    -> string
  val fromString : string -> int option
end

Implementations of integers

A selection...

structure Int :> INTEGER
                      where type int = int
structure Int31  :> INTEGER  (* optional *)
structure Int32  :> INTEGER  (* optional *)
structure Int64  :> INTEGER  (* optional *)
structure IntInf :> INTEGER  (* optional *)

What about natural numbers?

signature NATURAL = sig
   ...
end

And bignums!

functor 
    BignumFn(Nat:NATURAL) :> INTEGER = ...

24 April 2013: More ML modules examples

Preliminary: Online course evaluations

Notes:

Board:

ML Modules examples, part II

          *** Queues in Standard ML ***
signature QUEUE = sig
  type 'a queue    (* another abstract type *)
  exception Empty

  val empty : 'a queue
  val put : 'a * 'a queue -> 'a queue
  val get : 'a queue -> 'a * 'a queue   (* raises Empty *)

  (* LAWS:  get(put(a, empty))     ==  (a, empty)
      fst(get(put(a, put(a', q)))) == fst(get(put(a', q)))
      snd(get(put(a, put(a', q)))) == 
                              put(a, snd(get(put(a', q))))
   *)
end

Extended example: Error tracking

Error modules, board: Three common implementations (all included on homework)

Your obligations: two types, three functions, algebraic laws

          *** Classic ``accumulator'' for errors ***
signature ERROR = sig
  type error   (* a single error *)
  type summary (* summary of what errors occurred *)

  val nothing : summary                  (* no errors *)
  val <+> : summary * summary -> summary (* combine *)

  val oneError : error -> summary

  (* laws:   nothing <+> s == s
             s <+> nothing == s
             s1 <+> (s2 <+> s3) == (s1 <+> s2) <+> s3    
                                        // associativity
   *)
end


          *** Combining generic computations ***
signature COMPUTATION = sig
  type 'a comp    (* Computation! When run, results in
                     value of type 'a or error summary *)

  val succeeds : 'a -> 'a comp   (* a computation 
                                    without errors *)

  val <$> : ('a -> 'b) * 'a comp -> 'b comp
               (* apply a pure function to a computation *)
  val <*> : ('a -> 'b) comp * 'a comp -> 'b comp
                      (* application inside computations *)

  val >>= : 'a comp * ('a -> 'b comp) -> 'b comp
                 (* computation followed by continuation *)
end


          *** {Buckets of \emph{generic} algebraic laws} ***
  succeeds x >>= k  == k a                  // identity
  comp >>= succeeds == comp                 // identity
  comp >>= (fn x => k x >>= h) == (comp >>= k) >>= h  
                                          // associativity
     // compare  comp >>= (fn x => comp') with
     //     "let x = comp in comp'"
     //     (fn x => comp') comp

  f <$> c == succeeds f <*> c
  (fn x => x) <$> c == c                       // identity
  curry (op o) <$> u <*> v <*> w == u <*> (v <*> w)
      // compare:  curry (op o) u' v' w' = u' (v' w')
  succeeds f <*> succeeds x == succeeds (f x)  // success


          *** Variation on environments ***
signature COMPENV = sig
  type 'a env   (* environment mapping strings
                   to values of type 'a *)
  type 'a comp  (* computation of 'a or
                   an error summary *)

  val lookup : string * 'a env -> 'a comp
end


          *** Payoff! ***
functor InterpFn(structure Error : ERROR
                 structure Comp  : COMPUTATION
                 structure Env   : COMPENV
                 val zerodivide : Error.error
                 val error : Error.error -> 'a Comp.comp
  (* LOOK --> *) sharing type Comp.comp = Env.comp) =
struct
  fun curry f x y = f (x, y)

  val (<*>, <$>, >>=) = (Comp.<*>, Comp.<$>, Comp.>>=)
  infix 4 <$>
  infix 3 <*> >>=
  ...
end


          *** SLIDE ***
datatype exp = LIT of int
             | VAR of string
             | PLUS of exp * exp
             | DIV  of exp * exp

fun eval (e, rho) =
 let fun ev(LIT n) = Comp.succeeds n
       | ev(VAR x) = Env.lookup (x, rho)
       | ev(PLUS (e1, e2)) = curry op + <$> ev e1 <*> ev e2
       | ev(DIV (e1, e2))  = ev e1 >>= (fn n1 =>
                             ev e2 >>= (fn n2 =>
                             case n2
                               of 0 => error zerodivide
                                | _ => Comp.succeeds
                                              (n1 div n2)))
 in  ev e
 end

26 April 2013: ML Modules wrapup

Preliminaries

Board:

eval e1 + eval e2

op + (eval e1, eval e2)

curry op + (eval e1) (eval e2)

curry op + <$> ev e1 <*> ev e2

Homework review:

Reading:

Return to Error-tracking example

What's going on in this example:

Computations are the big ambitious thing.

We're doing errors, but these can include:

Solutions:

fun (SUCC f) <*> (SUCC x) = SUCC (f x)     (* success law *)
  | (SUCC f) <*> (ERR s ) = ERR s
  | (ERR  s) <*> (SUCC x) = ERR s
  | (ERR  s) <*> (ERR s') = ERR (Error.<+> (s, s'))

fun f <$> c = succeeds f <*> c

fun (SUCC a) >>= k = k a
  | (ERR  s) >>= _ = ERR s

29 April 2013: Retrospective and prospective

1970s: What is logic programming?

1980s onward: What are the descendants of Smalltalk?

2010s: How is functional programming used today?


Back to class home page