remove dead examples

svn: r16480
This commit is contained in:
Sam Tobin-Hochstadt 2009-10-30 16:27:55 +00:00
parent 93a504a817
commit 40bc4cb77a
6 changed files with 0 additions and 1130 deletions

View File

@ -1,238 +0,0 @@
#reader (planet "typed-reader.ss" ("plt" "typed-scheme.plt"))
(module hw02 "../../typed-scheme.ss"
(require "support.ss")
;;; --------------------------------------------------------------------
;;; Question 1
;; list-product : (list-of number) (list-of number) -> number
;; computes the dot-product of two lists (as vector representations)
;; (Assumes the two inputs are of equal length)
(define: (list-product [l1 : (Listof number)] [l2 : (Listof number)]) : number
(foldl #{+ :: (number number -> number)} 0 (map #{* :: (number number -> number)} l1 l2)))
;; tests
(test (list-product '(1 2 3) '(4 5 6)) => 32)
(test (list-product '() '()) => 0)
;;; --------------------------------------------------------------------
;;; Question 2
#|
<AE> ::= <AE> + <fac>
| <AE> - <fac>
| <fac>
<fac> ::= <fac> * <atom>
| <fac> / <atom>
| <atom>
<atom> ::= <number>
| + <atom>
| - <atom>
| ( <AE> )
In the rules for <atom>, note that any number of unary +/-
operators can be used, and that the resulting grammar is not
ambiguous since they are put in yet another level below <fac> (they
have higher precedence than the binary operators).
|#
;;; --------------------------------------------------------------------
;;; Question 3
;; [3a]
(define-type BINTREE
[Node (l BINTREE) (r BINTREE)]
[Leaf (n number)])
;; used for tests:
(define: 1234-tree : BINTREE
(Node (Node (Leaf 1) (Leaf 2))
(Node (Leaf 3) (Leaf 4))))
(define: 528-tree : BINTREE (Node (Leaf 5) (Node (Leaf 2) (Leaf 8))))
#;(provide (all-defined))
#| [3b] BNF:
<BINTREE> ::= <Node> | <Leaf>
<Node> ::= (Node <BINTREE> <BINTREE>)
<Leaf> ::= (Leaf <num>)
|#
;; [3c]
;; tree-reduce : BINTREE (num num -> num) -> num
;; Reduces a BINTREE to a number by descending recursively and combining
;; results with `op'.
(define: (tree-reduce [tree : BINTREE] [op : (number number -> number)]) : number
(cases tree
[(Node l r) (op (tree-reduce l op) (tree-reduce r op))]
[(Leaf n) n]))
;; tests:
(test 10 <= (tree-reduce 1234-tree +))
(test 10 <= (tree-reduce (Leaf 10) +))
(test 24 <= (tree-reduce 1234-tree *))
;; tree-min : BINTREE -> num
;; Finds the minimum number in a BINTREE.
(define: (tree-min [tree : BINTREE]) : number
(tree-reduce tree min))
;; tests:
(test 1 <= (tree-min 1234-tree))
(test 1 <= (tree-min (Leaf 1)))
;; tree-min : BINTREE -> num
;; Finds the maximum number in a BINTREE.
(define: (tree-max [tree : BINTREE]) : number
(tree-reduce tree max))
;; tests:
(test 4 <= (tree-max 1234-tree))
(test 1 <= (tree-max (Leaf 1)))
;; tree-sorted? : BINTREE -> bool
;; Tests whether the tree is sorted or not.
(define: (tree-sorted? [tree : BINTREE]) : boolean
(cases tree
[(Node l r) (and (tree-sorted? l)
(tree-sorted? r)
(<= (tree-max l) (tree-min r)))]
[(Leaf n) #t]))
;; tests:
(test (tree-sorted? 1234-tree))
(test (tree-sorted? (Leaf 1)))
(test (not (tree-sorted? 528-tree)))
#|
#| [3d]
Say that the cost function is cost(n) for a tree with n leaves, and
that we're given a balanced tree of 32 leaves. We have:
cost(32) = 16 ; for finding the max the left side
+ 16 ; for finding the min the right side
+ cost(16) ; for the recursive call on the left
+ cost(16) ; for the recursive call on the right
+ 1 ; some constant for the `and' and the `<'
In general, we can drop the last one since it doesn't matter and get:
cost(n) = 2*(n/2) + 2*cost(n/2) = n + 2*cost(n/2)
and
cost(1) = 1
Continueing with the case of 32:
cost(32) = 32 + 2*cost(16)
= 32 + 2*(16 + 2*cost(8))
= 32 + 32 + 4*cost(8)
= 32 + 32 + 32 + 8*cost(4)
= 32 + 32 + 32 + 32 + 16*cost(2)
= 32 + 32 + 32 + 32 + 32 + 32*cost(1)
= 32 + 32 + 32 + 32 + 32 + 32
So the total cost for n leaves is n*log2(n).
|#
;; 3e
;; tree-sorted*? : BINTREE -> bool
;; Tests whether the tree is sorted or not in linear time.
;; -- The trick is to check for sortedness by recursively walking the
;; tree and remembering the last value we have seen and making sure
;; that new leaves are always bigger. The return value of the helper
;; is either the right-most value if it is sorted, or #f if not.
(define (tree-sorted*? tree)
;; `and' is used to turn the result into a proper boolean
(and (sorted*?-helper
tree
(- (left-most-value tree) 1)) ; initialize a last value
#t))
;; left-most-value : BINTREE -> num
;; Finds the left-most value in a BINTREE.
(define (left-most-value tree)
(cases tree
[(Leaf n) n]
[(Node l r) (left-most-value l)]))
;; sorted*?-helper : BINTREE num -> bool-or-num
;; Helper for the above -- checks that the given tree is sorted and
;; bigger than the given number, and returns the right-most number if it
;; is sorted.
(define (sorted*?-helper tree last)
(cases tree
[(Leaf n)
(and (< last n) n)]
[(Node l r)
(let ([left-last (sorted*?-helper l last)])
(and left-last (sorted*?-helper r left-last)))]))
;; tests:
(test (tree-sorted*? 1234-tree))
(test (tree-sorted*? (Leaf 1)))
(test (not (tree-sorted*? 528-tree)))
;;; --------------------------------------------------------------------
;;; Question 4
;; tree-map : (num -> num) BINTREE -> BINTREE
;; Maps the given function recursively over the given tree, returning a
;; tree of the results with the same shape.
(define (tree-map f tree)
(cases tree
[(Leaf n) (Leaf (f n))]
[(Node l r) (Node (tree-map f l) (tree-map f r))]))
;; tests
(test (tree-map add1 (Node (Leaf 1) (Node (Leaf 2) (Leaf 3))))
=> (Node (Leaf 2) (Node (Leaf 3) (Leaf 4))))
(test (tree-map add1 1234-tree)
=> (Node (Node (Leaf 2) (Leaf 3)) (Node (Leaf 4) (Leaf 5))))
(test (tree-map add1 (Leaf 1))
=> (Leaf 2))
;;; --------------------------------------------------------------------
;;; Question 5
;; tree-insert : BINTREE num -> BINTREE
(define (tree-insert tree n)
(cases tree
[(Leaf m) (if (< n m)
(Node (Leaf n) tree)
(Node tree (Leaf n)))]
[(Node l r) (if (< n (tree-max l))
(Node (tree-insert l n) r)
(Node l (tree-insert r n)))]))
;; tests:
(test (tree-sorted?
(tree-insert (Node (Leaf 2) (Node (Leaf 4) (Leaf 6)))
3)))
(test (tree-sorted? (tree-insert 1234-tree 0)))
(test (tree-sorted? (tree-insert 1234-tree 5)))
;;; --------------------------------------------------------------------
;;; Question 6
#|
The problem is that we need to keep both flattened copies in memory
for the comparison. This means that if we have two big trees, say
200MB each, then during the comparison we will need to have 800MB of
RAM! The solution for this is very hard for now, but later in the
course we will see one easy way to solve it.
|#|#
)

View File

@ -1,275 +0,0 @@
#reader (planet "typed-reader.ss" ("plt" "typed-scheme.plt"))
(module hw03 "../../typed-scheme.ss"
(require "support.ss")
#| This is the updated Algae BNF definition:
<ALGAE> ::= <num>
| { + <ALGAE> ... }
| { - <ALGAE> <ALGAE> ... }
| { * <ALGAE> ... }
| { / <ALGAE> <ALGAE> ... }
| { = <ALGAE> <ALGAE> }
| { < <ALGAE> <ALGAE> }
| { <= <ALGAE> <ALGAE> }
| { if <ALGAE> <ALGAE> <ALGAE> }
| { with { <id> <ALGAE> } <ALGAE>}
| <id>
|#
(define-type ALGAE
[Num (n number)]
[Add (args (list-of ALGAE))]
;; note how Sub & Div match the corresponding BNF derivation
[Sub (fst ALGAE) (args (list-of ALGAE))]
[Mul (args (list-of ALGAE))]
[Div (fst ALGAE) (args (list-of ALGAE))]
[Eql (lhs ALGAE) (rhs ALGAE)]
[Less (lhs ALGAE) (rhs ALGAE)]
[LessEql (lhs ALGAE) (rhs ALGAE)]
[If (cond-expr ALGAE) (then-expr ALGAE) (else-expr ALGAE)]
[Id (name symbol)]
[With (name symbol) (named ALGAE) (body ALGAE)])
;; parse-sexpr : s-expr -> ALGAE
#;(define: (parse-sexpr [sexpr : Sexp]) : ALGAE
(cond
[(number? sexpr) (Num sexpr)]
[(symbol? sexpr) (Id sexpr)]
;; new code (needed because not doesn't work)
[(null? sexpr) (error 'parse-sexpr "bad syntax in ~s" sexpr)]
;; end new code
;; these next two have the horrid and trick.
[(and (list? sexpr) (not (null? sexpr))
(eq? 'with (first sexpr))
(let ([s (second sexpr)])
(if (list? s)
(if (= 2 (length s))
(let ([sym (first s)])
(if (symbol? sym)
(With sym
(parse-sexpr (second s))
(parse-sexpr (third sexpr)))
(error 'parse-sexpr "bad `with' syntax")))
(error 'parse-sexpr "bad `with' syntax"))
(error 'parse-sexpr "bad `with' syntax"))))]
[(and (list? sexpr) (not (null? sexpr))
(let ([subs (map parse-sexpr (rest sexpr))])
(case (first sexpr)
[(+) (Add subs)]
[(-) (if (null? subs)
(error 'parse-sexpr "need at least one arg for `-'")
(Sub (first subs) (rest subs)))]
[(*) (Mul subs)]
[(/) (if (null? subs)
(error 'parse-sexpr "need at least one arg for `/'")
(Div (first subs) (rest subs)))]
[(=) (if (= 2 (length subs))
(Eql (first subs) (second subs))
(error 'parse-sexpr "need two args for `='"))]
[(<) (if (= 2 (length subs))
(Less (first subs) (second subs))
(error 'parse-sexpr "need two args for `<'"))]
[(<=) (if (= 2 (length subs))
(LessEql (first subs) (second subs))
(error 'parse-sexpr "need two args for `<='"))]
[(if) (if (= 3 (length subs))
(If (first subs) (second subs) (third subs))
(error 'parse-sexpr "need three exprs for `if'"))]
[else (error 'parse-sexpr "don't know about ~s"
(first sexpr))])))]
[else (error 'parse-sexpr "bad syntax in ~s" sexpr)]))
;; parse : string -> ALGAE
;; parses a string containing an ALGAE expression to an ALGAE AST
#;(define: (parse [str : String]) : ALGAE
(parse-sexpr (string->sexpr str)))
#| Formal specs for `subst':
(`N' is a <num>, `E1', `E2' are <ALGAE>s, `x' is some <id>, `y' is a
*different* <id>)
N[v/x] = N
{+ E ...}[v/x] = {+ E[v/x] ...}
{- E1 E ...}[v/x] = {- E1[v/x] E[v/x] ...}
{* E ...}[v/x] = {* E[v/x] ...}
{/ E1 E ...}[v/x] = {/ E1[v/x] E[v/x] ...}
{= E1 E2}[v/x] = {= E1[v/x] E2[v/x]}
{< E1 E2}[v/x] = {< E1[v/x] E2[v/x]}
{<= E1 E2}[v/x] = {<= E1[v/x] E2[v/x]}
{if E1 E2 E3}[v/x] = {if E1[v/x] E2[v/x] E3[v/x]}
y[v/x] = y
x[v/x] = v
{with {y E1} E2}[v/x] = {with {y E1[v/x]} E2[v/x]}
{with {x E1} E2}[v/x] = {with {x E1[v/x]} E2}
|#
;; subst : ALGAE symbol ALGAE -> ALGAE
;; substitutes the second argument with the third argument in the
;; first argument, as per the rules of substitution; the resulting
;; expression contains no free instances of the second argument
(define: (subst [expr : ALGAE] [from : Symbol] [to : ALGAE]) : ALGAE
(let ([subst-list (lambda: ([exprs : (Listof ALGAE)])
(map (lambda: ([x : ALGAE]) (subst x from to)) exprs))])
(cases expr
[(Num n) expr]
[(Add args) (Add (subst-list args))]
[(Mul args) (Mul (subst-list args))]
[(Sub fst args) (Sub (subst fst from to) (subst-list args))]
[(Div fst args) (Div (subst fst from to) (subst-list args))]
[(Eql l r) (Eql (subst l from to) (subst r from to))]
[(Less l r) (Less (subst l from to) (subst r from to))]
[(LessEql l r) (LessEql (subst l from to) (subst r from to))]
[(If c t e) (If (subst c from to)
(subst t from to)
(subst e from to))]
[(Id id) (if (eq? id from) to expr)]
[(With bound-id named-expr bound-body)
(With bound-id
(subst named-expr from to)
(if (eq? bound-id from)
bound-body
(subst bound-body from to)))])))
(define: (subst2 [expr : ALGAE] [from : Symbol] [to : ALGAE]) : ALGAE
(let ([subst-list (lambda: ([exprs : (Listof ALGAE)])
(map (lambda: ([x : ALGAE]) (subst2 x from to)) exprs))])
(cond
[(Num? expr) expr]
[(Add? expr) (Add (subst-list (Add-args expr)))]
[(Mul? expr) (Mul (subst-list (Mul-args expr)))]
[(Sub? expr) (Sub (subst2 (Sub-fst expr) from to) (subst-list (Sub-args expr)))]
[(Div? expr) (Div (subst2 (Div-fst expr) from to) (subst-list (Div-args expr)))]
[(Eql? expr) (Eql (subst2 (Eql-lhs expr) from to) (subst2 (Eql-rhs expr) from to))]
[(Less? expr) (Less (subst2 (Less-lhs expr) from to) (subst2 (Less-rhs expr) from to))]
[(LessEql? expr) (LessEql (subst2 (LessEql-lhs expr) from to) (subst2 (LessEql-rhs expr) from to))]
[(If? expr) (If (subst2 (If-cond-expr expr) from to)
(subst2 (If-then-expr expr) from to)
(subst2 (If-else-expr expr) from to))]
[(Id? expr) (if (eq? (Id-name expr) from) to expr)]
[(With? expr)
(With (With-name expr)
(subst2 (With-named expr) from to)
(if (eq? (With-name expr) from)
(With-body expr)
(subst2 (With-body expr) from to)))])))
#| Formal specs for `eval':
eval(N) = N
eval({+ E ...}) = eval(E) + ...
eval({- E1}) = -eval(E1)
eval({- E1 E ...}) = eval(E1) - (eval(E) + ...)
eval({* E ...}) = eval(E1) * ...
eval({/ E1}) = 1/eval(E1)
eval({/ E1 E ...}) = eval(E1) / (eval(E) * ...)
eval({= E1 E2}) = 1 if eval(E1)=eval(E2), 0 otherwise
eval({< E1 E2}) = 1 if eval(E1)<eval(E2), 0 otherwise
eval({<= E1 E2}) = 1 if eval(E1)<=eval(E2), 0 otherwise
eval({if E1 E2 E3}) = eval(E3) if eval(E1)=0, eval(E2) otherwise
eval(id) = error!
eval({with {x E1} E2}) = eval(E2[eval(E1)/x])
|#
;; -eval : ALGAE -> number
;; evaluates ALGAE expressions by reducing them to numbers
(define: (-eval [expr : ALGAE]) : Number
(cases expr
[(Num n) n]
[(Add args) (foldl #{+ : (Number Number -> Number)} 0 (map -eval args))]
[(Mul args) (foldl #{* : (Number Number -> Number)} 1 (map -eval args))]
[(Sub fst args) (if (null? args)
(- (-eval fst))
(- (-eval fst) (foldl #{+ : (Number Number -> Number)} 0 (map -eval args))))]
[(Div fst args) (if (null? args)
(/ (-eval fst))
(/ (-eval fst) (foldl #{* : (Number Number -> Number)} 1 (map -eval args))))]
[(Eql l r) (if (= (-eval l) (-eval r)) 1 0)]
[(Less l r) (if (< (-eval l) (-eval r)) 1 0)]
[(LessEql l r) (if (<= (-eval l) (-eval r)) 1 0)]
[(If cond then else) (-eval (if (= 0 (-eval cond)) else then))]
[(With bound-id named-expr bound-body)
(-eval (subst bound-body bound-id (Num (-eval named-expr))))]
[(Id id) (error '-eval "free identifier: ~s" id)]))
;; run : string -> number
;; evaluate an ALGAE program contained in a string
#;(define: (run [str : String]) : Number
(-eval (parse str)))
;; previous tests
(test 5 <= (run "5"))
(test 10 <= (run "{+ 5 5}"))
(test 20 <= (run "{with {x {+ 5 5}} {+ x x}}"))
(test 10 <= (run "{with {x 5} {+ x x}}"))
(test 14 <= (run "{with {x {+ 5 5}} {with {y {- x 3}} {+ y y}}}"))
(test 4 <= (run "{with {x 5} {with {y {- x 3}} {+ y y}}}"))
(test 15 <= (run "{with {x 5} {+ x {with {x 3} 10}}}"))
(test 8 <= (run "{with {x 5} {+ x {with {x 3} x}}}"))
(test 10 <= (run "{with {x 5} {+ x {with {y 3} x}}}"))
(test 5 <= (run "{with {x 5} {with {y x} y}}"))
(test 5 <= (run "{with {x 5} {with {x x} x}}"))
;; new tests
(test 0 <= (run "{+}"))
(test 1 <= (run "{*}"))
(test -2 <= (run "{- 2}"))
(test 1/2 <= (run "{/ 2}"))
(test 1/2 <= (run "{/ 1 2}"))
(test 10 <= (run "{+ 1 2 3 4}"))
(test 2 <= (run "{if {< 2 3} 2 3}"))
(test 2 <= (run "{if {<= 3 3} 2 3}"))
(test 3 <= (run "{if {= 2 3} {/ 2 0} 3}"))
(test 1 <= (run "{+ {= 3 3} {< 3 2} {<= 3 2}}"))
(test 1 <= (run "{with {x 2} {= 1/8 {/ {* x 4}}}}"))
(test 1 <= (run "{with {x 2} {if {< 1 2} {<= 1 2} 3}}"))
;; test errors
(test (run "{-}") =error> "need at least")
(test (run "{/}") =error> "need at least")
(test (run "{= 1 2 3}") =error> "need two args")
(test (run "{< 1}") =error> "need two args")
(test (run "{<=}") =error> "need two args")
(test (run "{with 1}") =error> "bad * syntax")
(test (run "{with {x 1} y}") =error> "free identifier")
(test (run "{if 1}") =error> "need three")
(test (run "{foo 1}") =error> "don't know")
(test (run "{}") =error> "bad syntax in")
#| Dessert answer:
Adding `...' (or Kleene star) to our BNF language does not make it
more expressive. An informal proof: say that you have a BNF with
some use of `...' ("?" indicates unknown parts):
<FOO> ::= ? | ? <BAR> ... ? | ?
we can translate that to a BNF that does not use `...' by inventing a
fresh non-terminal (say that `<FOO1>' is not used elsewhere) and
rewriting the above derivation as follows:
<FOO> ::= ? | ? <FOO1> ? | ?
<FOO1> ::= <BAR> <FOO1>
| <-- an empty derivation
This can be systematically repeated, and the result will be an
ellipsis-free BNF that is equivalent to the original.
|#
#| Bonus answer
Yes, we could simulate `and' and `or' using arithmetics:
* use {* x y} instead of {and x y}
* use {+ {* x x} {* y y}} instead of {or x y}
... but that wouldn't be enough to do short circuiting and simulating
Scheme's `and' and `or', because these forms will evaluate *all* of
their subexpressions. To do that properly, we need more than
arithmetics: we need conditionals. For example:
* use {if x y 0} instead of {and x y}
* use {if x 1 y} instead of {or x y}
|#
)

View File

@ -1,349 +0,0 @@
#reader (planet "typed-reader.ss" ("plt" "typed-scheme.plt"))
(module hw04 "../../typed-scheme.ss"
(require "support.ss")
#| This is the updated Algae BNF definition:
<PROGRAM> ::= { program <FUN> ... }
<FUN> ::= { fun <id> { <id> } <ALGAE> }
<ALGAE> ::= <num>
| { + <ALGAE> ... }
| { - <ALGAE> <ALGAE> ... }
| { * <ALGAE> ... }
| { / <ALGAE> <ALGAE> ... }
| { = <ALGAE> <ALGAE> }
| { < <ALGAE> <ALGAE> }
| { <= <ALGAE> <ALGAE> }
| { if <ALGAE> <ALGAE> <ALGAE> }
| { with { <id> <ALGAE> } <ALGAE>}
| <id>
| { call <id> <ALGAE> }
|#
(define-type ALGAE
[Num (n number)]
[Add (args (list-of ALGAE))]
;; note how Sub & Div match the corresponding BNF derivation
[Sub (fst ALGAE) (args (list-of ALGAE))]
[Mul (args (list-of ALGAE))]
[Div (fst ALGAE) (args (list-of ALGAE))]
[Eql (lhs ALGAE) (rhs ALGAE)]
[Less (lhs ALGAE) (rhs ALGAE)]
[LessEql (lhs ALGAE) (rhs ALGAE)]
[If (cond-expr ALGAE) (then-expr ALGAE) (else-expr ALGAE)]
[Id (name symbol)]
[With (name symbol) (named ALGAE) (body ALGAE)]
[Call (fun symbol) (arg ALGAE)])
(define-type FUN
[Fun (name symbol) (arg symbol) (body ALGAE)])
(define-type PROGRAM
[Funs (funs (list-of FUN))])
;; parse-program : s-expr -> PROGRAM
;; parses a whole program s-expression into a PROGRAM
#;(define: (parse-program [sexpr : Sexp]) : PROGRAM
(if (and (list? sexpr)
(not (null? sexpr))
(eq? 'program (first sexpr)))
(Funs (map parse-fun (rest sexpr)))
(error 'parse-program "bad program syntax: ~s" sexpr)))
;; parse-fun : s-expr -> FUN
;; parses a function s-expression syntax to an instance of FUN
#;(define: (parse-fun [sexpr : Sexp]) : FUN
(if (and ;; check overall structure
(list? sexpr)
(= 4 (length sexpr))
(eq? 'fun (first sexpr))
;; check function name
(symbol? (second sexpr))
;; check argument in a sublist
(list? (third sexpr))
(= 1 (length (third sexpr)))
(symbol? (first (third sexpr))))
;; assemble the needed Fun parts
(Fun (second sexpr)
(first (third sexpr))
(parse-expr (fourth sexpr)))
(error 'parse-program "bad function syntax: ~s" sexpr)))
;; parse-expr : s-expr -> ALGAE
;; parses an s-expression into an ALGAE abstract syntax tree
#;(define: (parse-expr [sexpr : Sexp]) : ALGAE
(cond
[(number? sexpr) (Num sexpr)]
[(symbol? sexpr) (Id sexpr)]
[(and (list? sexpr) (not (null? sexpr))
(eq? 'with (first sexpr)))
(if (and (list? (second sexpr))
(= 2 (length (second sexpr)))
(symbol? (first (second sexpr))))
(With (first (second sexpr))
(parse-expr (second (second sexpr)))
(parse-expr (third sexpr)))
(error 'parse-expr "bad `with' syntax"))]
;; and trick
[(and (list? sexpr) (not (null? sexpr))
(eq? 'call (first sexpr)))
(if (and (= 3 (length sexpr)) (symbol? (second sexpr)))
(Call (second sexpr)
(parse-expr (third sexpr)))
(error 'parse-expr "bad `call' syntax"))]
;; and trick
[(and (list? sexpr) (not (null? sexpr)))
(let ([subs (map parse-expr (rest sexpr))])
(case (first sexpr)
[(+) (Add subs)]
[(-) (if (null? subs)
(error 'parse-expr "need at least one arg for `-'")
(Sub (first subs) (rest subs)))]
[(*) (Mul subs)]
[(/) (if (null? subs)
(error 'parse-expr "need at least one arg for `/'")
(Div (first subs) (rest subs)))]
[(=) (if (= 2 (length subs))
(Eql (first subs) (second subs))
(error 'parse-expr "need two args for `='"))]
[(<) (if (= 2 (length subs))
(Less (first subs) (second subs))
(error 'parse-expr "need two args for `<'"))]
[(<=) (if (= 2 (length subs))
(LessEql (first subs) (second subs))
(error 'parse-expr "need two args for `<='"))]
[(if) (if (= 3 (length subs))
(If (first subs) (second subs) (third subs))
(error 'parse-expr "need three exprs for `if'"))]
[else (error 'parse-expr "don't know about ~s"
(first sexpr))]))]
[else (error 'parse-expr "bad syntax in ~s" sexpr)]))
;; Bonus:
;; verify-functions : PROGRAM -> void
;; this function verifies the list of functions, and doesn't return any
;; useful value.
(define: (verify-functions [prog : PROGRAM]) : Any
;; this will fail if there is no `main' definition
(lookup-fun 'main prog)
;; check for repeating names, see helper below
(check-duplicates (map Fun-name (Funs-funs prog)) '())
;; finally, scan `Call' syntaxes
(check-calls-list (map Fun-body (Funs-funs prog)) prog))
;; check-duplicates : (list-of symbol) (list-of symbol) -> void
;; helper for `verify-functions'
(define: (check-duplicates [symbols : (Listof Symbol)] [seen : (Listof Symbol)]) : Any
;; `symbols' is what we check, `seen' is names we've already seen
(cond [(null? symbols) 'ok]
[(member (first symbols) seen)
(error 'verify-functions
"duplicate definition: ~s" (first symbols))]
[else (check-duplicates (rest symbols) ;; CHANGE
(cons (first symbols) seen))]))
;; helper for `verify-functions'
(define: (check-calls-list [funs : (Listof ALGAE)] [prog : PROGRAM]) : Any
(if (null? funs)
'ok
;; note that `and' is not really needed below, we just want to use
;; both expressions so everything is checked. Also in
;; `check-calls-expr'.
(and (check-calls-expr (first funs) prog)
(check-calls-list (rest funs) prog))))
(define: (check-calls-expr [expr : ALGAE] [prog : PROGRAM]) : Any
(cases expr
[(Num n) 'ok]
[(Add args) (check-calls-list args prog)]
[(Mul args) (check-calls-list args prog)]
[(Sub fst args) (check-calls-list (cons fst args) prog)]
[(Div fst args) (check-calls-list (cons fst args) prog)]
[(Eql l r) (and (check-calls-expr l prog)
(check-calls-expr r prog))]
[(Less l r) (and (check-calls-expr l prog)
(check-calls-expr r prog))]
[(LessEql l r) (and (check-calls-expr l prog)
(check-calls-expr r prog))]
[(If c t e) (and (check-calls-expr c prog)
(check-calls-expr t prog)
(check-calls-expr e prog))]
[(Id id) 'ok]
[(With bound-id named-expr bound-body)
(and (check-calls-expr named-expr prog)
(check-calls-expr bound-body prog))]
[(Call fun-name arg)
(and (lookup-fun fun-name prog)
(check-calls-expr arg prog))]))
;; parse : string -> PROGRAM
;; parses a string containing an ALGAE program to a PROGRAM instance
#;(define (parse str)
(let ([prog (parse-program (string->sexpr str))])
;; Bonus answer: the reason we use two expressions is that
;; `verify-functions' can only signal errors, so it is used only for
;; its side effect.
(verify-functions prog)
prog))
;; subst : ALGAE symbol ALGAE -> ALGAE
;; substitutes the second argument with the third argument in the
;; first argument, as per the rules of substitution; the resulting
;; expression contains no free instances of the second argument
(define: (subst [expr : ALGAE] [from : symbol] [to : ALGAE]) : ALGAE
(let ([subst-list (lambda: ([exprs : (Listof ALGAE)])
(map (lambda: ([x : ALGAE]) (subst x from to)) exprs))])
(cases expr
[(Num n) expr]
[(Add args) (Add (subst-list args))]
[(Mul args) (Mul (subst-list args))]
[(Sub fst args) (Sub (subst fst from to) (subst-list args))]
[(Div fst args) (Div (subst fst from to) (subst-list args))]
[(Eql l r) (Eql (subst l from to) (subst r from to))]
[(Less l r) (Less (subst l from to) (subst r from to))]
[(LessEql l r) (LessEql (subst l from to) (subst r from to))]
[(If c t e) (If (subst c from to)
(subst t from to)
(subst e from to))]
[(Id id) (if (eq? id from) to expr)]
[(With bound-id named-expr bound-body)
(With bound-id
(subst named-expr from to)
(if (eq? bound-id from)
bound-body
(subst bound-body from to)))]
[(Call fun-name arg) (Call fun-name (subst arg from to))])))
;; lookup-fun : symbol PROGRAM -> FUN
;; looks up a FUN instance in a PROGRAM given its name
(define: (lookup-fun [name : Symbol] [prog : PROGRAM]) : FUN
(cases prog
[(Funs funs)
(or (ormap (lambda: ([fun : FUN])
;; `ormap' will return the first true (= non-#f)
;; result, so this is both a predicate and returning
;; the value that is used
(cases fun
[(Fun fname arg expr) (and (eq? fname name) fun)]))
funs)
(error 'lookup-fun
"missing function definition for: ~s" name))]))
;; eval : ALGAE PROGRAM -> number
;; evaluates ALGAE expressions by reducing them to numbers
;; `prog' is provided for function lookup
(define: (-eval [expr : ALGAE] [prog : PROGRAM]) : Number
;; note the scoping rules: the following function will call the real
;; eval, but it expects a single argument, and always uses `prog'
(let ([-eval (lambda: ([expr : ALGAE]) (-eval expr prog))])
(cases expr
[(Num n) n]
[(Add args) (foldl #{+ :: (Number Number -> Number)} 0 (map -eval args))]
[(Mul args) (foldl #{* :: (Number Number -> Number)} 1 (map -eval args))]
[(Sub fst args) (if (null? args)
(- (-eval fst))
(- (-eval fst) (foldl #{+ :: (Number Number -> Number)} 0 (map -eval args))))]
[(Div fst args) (if (null? args)
(/ (-eval fst))
(/ (-eval fst) (foldl #{* :: (Number Number -> Number)} 1 (map -eval args))))]
[(Eql l r) (if (= (-eval l) (-eval r)) 1 0)]
[(Less l r) (if (< (-eval l) (-eval r)) 1 0)]
[(LessEql l r) (if (<= (-eval l) (-eval r)) 1 0)]
[(If cond then else) (-eval (if (= 0 (-eval cond)) else then))]
[(With bound-id named-expr bound-body)
(-eval (subst bound-body bound-id (Num (-eval named-expr))))]
[(Id id) (error '-eval "free identifier: ~s" id)]
[(Call fun-name arg)
(cases (lookup-fun fun-name prog)
[(Fun name bound-id body)
(-eval (subst body bound-id (Num (-eval arg))))])])))
;; run : string number -> number
;; evaluate an ALGAE complete program contained in a string using a
;; given value
#;(define: (run [str : String] [arg : Number]) : Number
(let ([prog (parse str)])
(-eval (Call 'main (Num arg)) prog)))
;; big test
(test (run "{program
{fun even? {n}
{if {= 0 n} 1 {call odd? {- n 1}}}}
{fun odd? {n}
{if {= 0 n} 0 {call even? {- n 1}}}}
{fun main {n}
{if {= n 1}
1
{+ 1 {call main
{if {call even? n}
{/ n 2}
{+ 1 {* n 3}}}}}}}}"
3)
=> 8)
;; test cases for full coverage
(test (run "1" 1)
=error> "bad program syntax")
(test (run "{program 1}" 1)
=error> "bad function syntax")
(test (run "{program {fun main {x} {with {y 1} {+ x y}}}}" 1)
=> 2)
(test (run "{program {fun main {x} {with {foo 1} {call foo foo}}}
{fun foo {x} {- x -1}}}"
1)
=> 2)
(test (run "{program {fun main {x} {with y {+ x y}}}}" 1)
=error> "bad `with' syntax")
(test (run "{program {fun main {x} {call 1 2}}}" 1)
=error> "bad `call' syntax")
(test (run "{program {fun main {x} {-}}}" 1)
=error> "need at least one")
(test (run "{program {fun main {x} {/}}}" 1)
=error> "need at least one")
(test (run "{program {fun main {x} {=}}}" 1)
=error> "need two args")
(test (run "{program {fun main {x} {< 1}}}" 1)
=error> "need two args")
(test (run "{program {fun main {x} {<=}}}" 1)
=error> "need two args")
(test (run "{program {fun main {x} {if 1 2 3 4}}}" 1)
=error> "need three exprs")
(test (run "{program {fun main {x} {main 1}}}" 1)
=error> "don't know about")
(test (run "{program {fun main {x} {}}}" 1)
=error> "bad syntax in")
(test (run "{program {fun main {x} x} {fun main {x} x}}" 1)
=error> "duplicate definition")
(test (run "{program {fun main {x} {call foo x}}}" 1)
=error> "missing function definition")
(test (run "{program {fun main {x} y}}" 1)
=error> "free identifier")
(test (run "{program
{fun main {x}
{*{+{*{+{*}{*}}{+{*}{*}{*}{*}}{+{*}{*}{*}{*}}}{*}}
{+{*}{*}{*}{*}{*}}
{+{*}{*}{*}{*}}}}}" 1)
=> 660)
(test (run "{program {fun main {x} {+ {< x 3} {<= x 3} {= x 3}}}}" 1)
=> 2)
(test (run "{program {fun main {x} {+ {< x 3} {<= x 3} {= x 3}}}}" 3)
=> 2)
(test (run "{program {fun main {x} {+ {< x 3} {<= x 3} {= x 3}}}}" 4)
=> 0)
(test (run "{program {fun main {x} {* {- x} {/ x}}}}" 2)
=> -1)
(test (run "{program {fun main {x} {with {x 2} x}}}" 1)
=> 2)
;; can't check `run' since we won't check that the error happend when
;; parsing
(test (parse "{program {fun foo {x} x}}")
=error> "missing function definition for: main")
(test (parse "{program {fun main {x} {call bar x}} {fun foo {x} x}}")
=error> "missing function definition for: bar")
;; test that the language is not higher order
(test 1 <= (run "{program {fun foo {foo} foo}
{fun main {foo} {call foo foo}}}"
1))
)

View File

@ -1,222 +0,0 @@
#reader(planet "typed-reader.ss" ("plt" "typed-scheme.plt"))
(module hw05 "../../typed-scheme.ss"
(require "support.ss")
#|
The grammar:
<BRANG> ::= <num>
| { + <BRANG> <BRANG> }
| { - <BRANG> <BRANG> }
| { * <BRANG> <BRANG> }
| { / <BRANG> <BRANG> }
| { with { <id> <BRANG> } <BRANG> }
| <id>
| { fun { <id> } <BRANG> }
| { call <BRANG> <BRANG> }
Evaluation rules:
eval(N,env) = N
eval({+ E1 E2},env) = eval(E1,env) + eval(E2,env)
eval({- E1 E2},env) = eval(E1,env) - eval(E2,env)
eval({* E1 E2},env) = eval(E1,env) * eval(E2,env)
eval({/ E1 E2},env) = eval(E1,env) / eval(E2,env)
eval(Ref(N),env) = list-ref(env,N)
eval({with {x E1} E2},env) = eval(E2,cons(eval(E1,env),env))
eval({fun {x} E},env) = <{fun {x} E},env>
eval({call E1 E2},env1) = eval(Ef,cons(eval(E2,env1),env2))
if eval(E1,env1)=<{fun {x} Ef},env2>
= error! otherwise
|#
;; input syntax
(define-type BRANG
[Num (n number)]
[Add (lhs BRANG) (rhs BRANG)]
[Sub (lhs BRANG) (rhs BRANG)]
[Mul (lhs BRANG) (rhs BRANG)]
[Div (lhs BRANG) (rhs BRANG)]
[Id (name symbol)]
[With (name symbol) (named BRANG) (body BRANG)]
[Fun (name symbol) (body BRANG)]
[Call (fun-expr BRANG) (arg-expr BRANG)])
;; preprocessed syntax
(define-type BRANG*
[Num* (n number)]
[Add* (lhs BRANG*) (rhs BRANG*)]
[Sub* (lhs BRANG*) (rhs BRANG*)]
[Mul* (lhs BRANG*) (rhs BRANG*)]
[Div* (lhs BRANG*) (rhs BRANG*)]
[Ref* (idx Number)]
[With* (named BRANG*) (body BRANG*)]
[Fun* (body BRANG*)]
[Call* (fun-expr BRANG*) (arg-expr BRANG*)])
;; parse-sexpr : s-expr -> BRANG
#;(define (parse-sexpr sexpr)
(cond [(number? sexpr) (Num sexpr)]
[(symbol? sexpr) (Id sexpr)]
[(and (list? sexpr)
(not (null? sexpr))
(eq? 'with (first sexpr)))
(if (and (= 3 (length sexpr))
(list? (second sexpr))
(= 2 (length (second sexpr)))
(symbol? (first (second sexpr))))
(With (first (second sexpr))
(parse-sexpr (second (second sexpr)))
(parse-sexpr (third sexpr)))
(error 'parse-sexpr "bad `with' syntax"))]
[(and (list? sexpr)
(not (null? sexpr))
(eq? 'fun (first sexpr)))
(if (and (= 3 (length sexpr))
(list? (second sexpr))
(= 1 (length (second sexpr)))
(symbol? (first (second sexpr))))
(Fun (first (second sexpr))
(parse-sexpr (third sexpr)))
(error 'parse-sexpr "bad `fun' syntax"))]
[(and (list? sexpr) (= 3 (length sexpr)))
(let ([make-node
(case (first sexpr)
[(+) Add]
[(-) Sub]
[(*) Mul]
[(/) Div]
[(call) Call]
[else (error 'parse-sexpr "don't know about ~s"
(first sexpr))])])
(make-node (parse-sexpr (second sexpr))
(parse-sexpr (third sexpr))))]
[else (error 'parse-sexpr "bad syntax in ~s" sexpr)]))
;; parse : string -> BRANG
;; parses a string containing an BRANG expression to a BRANG AST
#;(define (parse str)
(parse-sexpr (string->sexpr str)))
;; These are the values of our language
(define-type VAL
[NumV (n number)]
[FunV (body BRANG*) (env ENV)])
;; NEW
(define-type-alias ENV (Listof VAL))
;; An environment is a simple list of values
;(define ENV? (list-of VAL?))
;; Syntactic environments for the de-Bruijn preprocessing:
;; define a type and an empty environment
;; this is represented by procedures, but the type should be:
;; DE-ENV := symbol -> integer
;; NEW
(define-type-alias DE-ENV (Symbol -> Number))
;; de-empty-env : DE-ENV
;; the empty syntactic environment, always throws an error
(define: (de-empty-env [id : Symbol]) : Number
(error 'de-env "Free identifier: ~s" id))
;; de-extend : DE-ENV symbol -> DE-ENV
;; extends a given de-env for a new identifier
(define: (de-extend [env : DE-ENV] [id : Symbol]) : DE-ENV
(lambda: ([name : Symbol])
(if (eq? id name)
0
(+ 1 (env name)))))
;; test
#;(test (let ([e (de-extend (de-extend de-empty-env 'b) 'a)])
(map (lambda (id) (e id))
'(a b)))
=> '(0 1))
;; preprocess : BRANG DE-ENV -> BRANG*
;; replaces identifier expressions into Ref AST values
(define: (preprocess [expr : BRANG] [de-env : DE-ENV]) : BRANG*
(let ([sub (lambda: ([expr : BRANG]) (preprocess expr de-env))])
(cases expr
[(Num n) (Num* n)]
[(Add l r) (Add* (sub l) (sub r))]
[(Sub l r) (Sub* (sub l) (sub r))]
[(Mul l r) (Mul* (sub l) (sub r))]
[(Div l r) (Div* (sub l) (sub r))]
[(With bound-id named-expr bound-body)
(With* (sub named-expr)
(preprocess bound-body (de-extend de-env bound-id)))]
[(Id id) (Ref* (de-env id))]
[(Fun bound-id bound-body)
(Fun* (preprocess bound-body (de-extend de-env bound-id)))]
[(Call fun-expr arg-expr)
(Call* (sub fun-expr) (sub arg-expr))])))
;; arith-op : (num num -> num) VAL VAL -> VAL
;; gets a Scheme numeric binary operator, and uses it within a NumV
;; wrapper
(define: (arith-op [op : (Number Number -> Number)] [val1 : VAL] [val2 : VAL]) : VAL
(define: (NumV->number [v : VAL]) : Number
(cases v
[(NumV n) n]
[else (error 'arith-op "expects a number, got: ~s" v)]))
(NumV (op (NumV->number val1) (NumV->number val2))))
;; eval : BRANG* env -> VAL
;; evaluates BRANG* expressions by reducing them to values
(define: (-eval [expr : BRANG*] [env : ENV]) : VAL
(cases expr
[(Num* n) (NumV n)]
[(Add* l r) (arith-op + (-eval l env) (-eval r env))]
[(Sub* l r) (arith-op - (-eval l env) (-eval r env))]
[(Mul* l r) (arith-op * (-eval l env) (-eval r env))]
[(Div* l r) (arith-op / (-eval l env) (-eval r env))]
[(With* named-expr bound-body)
(-eval bound-body (cons (-eval named-expr env) env))]
[(Ref* n) (list-ref env n)]
[(Fun* bound-body) (FunV bound-body env)]
[(Call* fun-expr arg-expr)
(let ([fval (-eval fun-expr env)])
(cases fval
[(FunV bound-body f-env)
(-eval bound-body (cons (-eval arg-expr env) f-env))]
[else (error '-eval "`call' expects a function, got: ~s"
fval)]))]))
#|
;; run : string -> number
;; evaluate a BRANG program contained in a string
(define (run str)
(let ([result (-eval (preprocess (parse str) de-empty-env) null)])
(cases result
[(NumV n) n]
[else (error 'run
"evaluation returned a non-number: ~s" result)])))
;; tests
(test (run "{call {fun {x} {+ x 1}} 4}")
=> 5)
(test (run "{with {add3 {fun {x} {+ x 3}}}
{call add3 1}}")
=> 4)
(test (run "{with {add3 {fun {x} {+ x 3}}}
{with {add1 {fun {x} {+ x 1}}}
{with {x 3}
{call add1 {call add3 x}}}}}")
=> 7)
(test (run "{with {identity {fun {x} x}}
{with {foo {fun {x} {+ x 1}}}
{call {call identity foo} 123}}}")
=> 124)
(test (run "{with {x 3}
{with {f {fun {y} {+ x y}}}
{with {x 5}
{call f 4}}}}")
=> 7)
(test (run "{call {call {fun {x} {call x 1}}
{fun {x} {fun {y} {+ x y}}}}
123}")
=> 124)
|#)

View File

@ -1,25 +0,0 @@
(module slow "../../typed-scheme.ss"
(require "../../CSU660/datatype.ss")
(define-type BINTREE
[Node (l BINTREE) (r BINTREE)]
[Leaf (n number)]
[Q ]
[Q1 ]
[Q2 ]
[Q3 ]
[Q4 ]
[Q5 ]
)
(cases (Leaf 1)
[(Node (Node (Node (Node (Node zz z) x) a) e) b) a]
[(Node a b) a]
[(Q) 1]
[(Q1) 1]
[(Q2) 1]
[(Q3) 1]
[(Q4) 1]
[(Q5) 1]
[(Leaf l) l]))

View File

@ -1,21 +0,0 @@
(module support "../../typed-scheme.ss"
(require (for-syntax scheme/base))
(provide sqr test first second third fourth string->sexpr rest foldl)
(define: (sqr [a : number]) : number (* a a))
(define-type-alias SExp (mu s (Un Number Boolean String Symbol (Listof s))))
(define-syntax (test stx) #'#f)
(pdefine: (a) (first [x : (Listof a)]) : a (car x))
(pdefine: (a) (second [x : (Listof a)]) : a (car (cdr x)))
(pdefine: (a) (third [x : (Listof a)]) : a (car (cdr (cdr x))))
(pdefine: (a) (fourth [x : (Listof a)]) : a (car (cdr (cdr (cdr x)))))
(pdefine: (a) (rest [x : (Listof a)]) : (Listof a) (cdr x))
(define: (string->sexpr [s : String]) : Sexp
(read (open-input-string s)))
#;(define: (list-of [f : (Any -> Any)]) : Any
(lambda: ([l : List]) (andmap f l)))
)