Commit 7f50e02f authored by James R. Wilcox's avatar James R. Wilcox
Browse files

lecture code for today

parent 8d75a1b7
(+ 1 2)
(define x (+ 1 2))
(define y (+ x 1))
(define (f x) (+ x 1))
(f y)
(define (pow b e)
(if (= e 0)
1
(* b (pow b (- e 1)))))
(pow 2 3)
(pow 10 7)
(define (countdown n)
(if (= n 0)
nil
(cons n (countdown (- n 1)))))
(countdown 10)
(define (sum l)
(if (nil? l)
0
(+ (car l) (sum (cdr l)))))
(sum (countdown 10))
(struct myrecord name present)
(define r (myrecord 'james true))
(myrecord-name r)
(myrecord-present r)
(myrecord? r)
(myrecord? (cons r 17))
(struct cheese)
(struct custom msg)
(define p1 (cheese))
(define p2 (custom 'olives))
(define (or x y) ;; warning! does not shortcircuit
(if x true y))
(define (pizza? p)
(or (cheese? p) (custom? p)))
(pizza? p1)
(pizza? p2)
(pizza? 17)
(pizza? (cons p1 p2))
; nil is almost like (struct nil) plus (define nil (nil))
; cons is almost like (struct cons car cdr) plus (define (car x) (cons-car x)) (define (cdr x) (cons-cdr x))
(struct constant num)
(struct plus e1 e2)
(define (eval e)
(if (constant? e)
(constant-num e)
(if (plus? e)
(+ (eval (plus-e1 e))
(eval (plus-e2 e)))
'error)))
(eval (plus (constant 1) (constant 2)))
(define (eval e)
(cond
((constant? e) (constant-num e))
((plus? e)
(+ (eval (plus-e1 e))
(eval (plus-e2 e))))))
(eval (plus (constant 1) (constant 2)))
; k is anything
; l is a list of pairs
; returns the first pair of l whose first component is equal to k
; or nil if no such pair
; note: returns the *pair* on success -- you have to call cdr to get the value
; (why did james do it this way?)
(define (assoc k l)
(if (nil? l)
nil
(if (= k (car (car l)))
(car l)
(assoc k (cdr l)))))
(struct variable symbol)
(define (eval dynenv e)
(cond
((variable? e) (cdr (assoc (variable-symbol e) dynenv)))
((constant? e) (constant-num e))
((plus? e)
(+ (eval dynenv (plus-e1 e))
(eval dynenv (plus-e2 e))))))
(eval nil (constant 3))
(eval nil (plus (constant 1) (constant 2)))
(eval (cons (cons 'x 17) nil)
(plus (constant 1) (variable 'x)))
; it's alive
(+ 1 2)
(define x (+ 1 2))
(define y (+ x 1))
(define (f x) (+ x 1))
(f y)
(define (pow b e)
(if (= e 0)
1
(* b (pow b (- e 1)))))
(pow 2 3)
(pow 10 7)
(define (countdown n)
(if (= n 0)
nil
(cons n (countdown (- n 1)))))
(countdown 10)
(define (sum l)
(if (nil? l)
0
(+ (car l) (sum (cdr l)))))
(sum (countdown 10))
;;; remember "Ocaml records as structs"
;;; type myrecord = { name: string; present: bool }
(struct myrecord name present)
; generates several things
; - constructor: like a function with the same name as the struct
; - builds values of tye myrecord type
; - accessor functions for each field (james calls these projections on accident; just ignore him)
; - each function gets the corresponding field
; - look later for "predicates" to see the last thing that gets generated
(define r (myrecord 17 true))
(myrecord-name r)
(myrecord-present r)
;;; remember "Ocaml variants as structs"
;;; type pizza = Cheese | Custom of string
; rule is: for each constructor of the OCaml variant type, introduce a trefoil struct
(struct cheese)
(struct custom instructions)
(define p1 (cheese))
(define p2 (custom 'only-olives)) ; "fake strings" aka symbols
; Symbols:
; must start with an apostrophe
; have no spaces
; other than that, they're pretty much strings
; you can't do anything to them except (= ... ) comparison
;;; in OCaml:
; p has type pizza
; match p with
; | Cheese -> "cheese"
; | Custom msg -> "a custom pizza: " ^ msg
; the last thing that a struct declaration generates
; - a "predicate function", whose name is the name of the struct plus "?"
; - returns true if its argument was built with the constructor of this struct
; and false otherwise
p1
(cheese? p1)
p2
(cheese? p2)
(cheese? 17)
(custom? p1)
(custom? p2)
;; similarities to nil/cons
; built-in value nil is almost like
; (struct nil)
; (define l (nil)) ;; would be an error if we didn't have built-in nil
;
; ; could work around that with
; ; (define nil (nil))
; built-in cons constructor is almost like
; (struct cons car cdr)
; (define new-pair (cons 1 2)) ; if we deleted built-in cons, this would build values of our new struct
;
; ; would require slightly different names for accessors
; (cons-car new-pair)
; (cons-cdr new-pair)
; could work around that
; (define (car x) (cons-car x))
; (define (cdr x) (cons-cdr x))
;; OCaml:
;; type expr = Constant of int | Plus of expr * expr
;;
;; let example = Plus(Constant(1), Constant(2))
;;
;; let rec eval (e: expr) =
;; match e with
;; | Constant(n) -> n
;; | Plus(e1, e2) -> eval e1 + eval e2
; an expression is either a constant or a plus
(struct constant num)
(struct plus e1 e2)
(define example
(plus
(constant 1)
(constant 2)))
; given an expression, evaluate it to its value
(define (eval e)
(if (constant? e)
(constant-num e)
(if (plus? e)
(+ (eval (plus-e1 e))
(eval (plus-e2 e)))
'error)))
(eval example)
; syntax of cond:
;
; (cond (p1 b1) ... (pn bn))
;
; (n can be zero)
; all of the the p_i and b_i are expressions
; semantics of cond:
;
; evaluate p1 to a value v1. if v1 is false, "keep going"
; otherwise, evaluate b1 and return that as the value for the whole cond
; to keep going, evaluate p2 and so on
;
; if you get through all the p_i and none are truthy, signal an error
;; old version
; (define (eval e)
; (if (constant? e)
; (constant-num e)
; (if (plus? e)
; (+ (eval (plus-e1 e))
; (eval (plus-e2 e)))
; 'error)))
;; new version with cond
(define (eval e)
(cond
((constant? e) (constant-num e))
((plus? e)
(+ (eval (plus-e1 e))
(eval (plus-e2 e))))
(true 'error)))
(eval example)
\ No newline at end of file
(* in Java, we had a superclass for expressions, and then one subclass per kind of expression *)
(* in OCaml, we have one giant variant type for expressions, with one constructor per kind *)
type expr =
| Constant of int
| Plus of expr * expr
(* add a new kind of expression: add a constructor to the expr type *)
| Minus of expr * expr
| Variable of string
(* in Java, used hash maps and lots of copying to implement dynamic environment *)
(* in OCaml, we will use an "association list":
- list of pairs
- each pair's first element is a "key"
- second element is a "value"
lookup elements in the list by recursion, searching for a key.
add elements to the list with cons
*)
type association_list = (string * expr) list
type dynamic_environment = association_list
let rec lookup ((assoc_list : association_list), (key: string)): expr =
match assoc_list with
| [] -> failwith "lookup failed to find key"
| (key', v) :: list ->
if key' = key
then v
else lookup (list, key)
let rec eval(dynenv, e) =
(* in Java, we would do instanceof checks to figure out what kind of expression *)
(* in OCaml, we use pattern matching *)
match e with
| Constant(n) -> n
| Plus(e1, e2) -> eval (dynenv, e1) + eval (dynenv, e2)
| Minus(e1, e2) -> eval (dynenv, e1) - eval (dynenv, e2)
| Variable(x) ->
(* look up x in the dynamic environment. *)
lookup (dynenv, x)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment