;; My solution (named interp-dave).
;; Used to compare with student's interp function.
;; helper function is named getval
;; getval consumes either a list or a number and produces a number.
;;
;; (getval e) determines whether e is a number or a list.
;; if it is a number, the number is returned.
;; if e is a list, getval evaluates the list by calling
;; interp on it and returns the value produces by interp
(define (getval e)
(cond
[(list? e) (interp e)]
[(number? e) e]
[ else
(error 'geval "Unknown thingy!")]))
;; ============================================================
;; NOTE: for grading this is called interp-dave, but this is the
;; same function as interp...
;; interp consumes a list and produces a number.
;;
;; (interp l) evaulate lists that contain elements according to the
;; rules below. Note that each list l described some computation to
;; be performed, interp does this computation.
;;
;; valid lists contain 3 elements. The middle element must be one of
;; the following: 'plus, 'minus, 'times, 'div. These correspond to the
;; arithmetic operations addition, subtraction, multplication and division.
;;
;; the first and last elements of l must either be numbers, or lists
;; which follow the same rules as the format for l.
;;
;; sample usage:
;; (interp '(3 plus 5))
(define (interp-dave l)
(cond
;; doing addition? if so use getval to evaluate the first and third
;; elements of l, then do the addition
[(symbol=? (first (rest l)) 'plus)
(+ (getval (first l)) (getval (third l)))]
;; doing subtraction? if so use getval to evaluate the first and third
;; elements of l, then do the subtraction
[(symbol=? (first (rest l)) 'minus)
(- (getval (first l)) (getval (third l)))]
;; doing multiplication? if so use getval to evaluate the first and third
;; elements of l, then do the multiply
[(symbol=? (first (rest l)) 'times)
(* (getval (first l)) (getval (third l)))]
;; doing division? if so use getval to evaluate the first and third
;; elements of l, then do the divide
[(symbol=? (first (rest l)) 'div)
(/ (getval (first l)) (getval (third l)))]
[ else
;; oops - unknown operator
(error 'interp "Unknown operator")]))
;;
;; =============================================================
;; CODE BELOW IS USED FOR TESTING INTERP FUNCTIONS
;;
;; code to generate random expressions and test student's interp function
;; num prob is the probability of generating a random number in an expression
;; rather than generating a nested expression. Set to 20% now.
(define numprob 20)
;;
;; generate_quiz5_test consumes a number and produces a list.
;;
;; (generate_quiz5_test num) generates a list that can be fed to
;; an interp function. The list may include nested lists (expressions),
;; the maximum depth of these expressions is controlled by num.
;;
;; This function generates a single (non-nested) expression if num is 0.
;; In this case it randomly picks an operator and two numbers in the range
;; [-500,-1],[1,500] - it avoids zero so we don't have to worry about possible
;; division by 0.
;;
;; If num is > 0, the list generated will have a random operator, and with probability
;; numprob (defined above) will generate a random number as the left/right values of the
;; expression. With probability 100-numprob, the left(right) will not be a number, but will
;; instead be another expression (created recursively with num set to num-1).
(define (generate_quiz5_test num)
(cond
;; hit max depth - generate leaf expression
[(= num 0) (quiz5_random_expression)]
[ else
;; not maximum depth - generate a possibly complex expression
(list
;; first element is a number with probability numprob,
;; an expression with probability 100-numprob.
(cond
[ (< numprob (random 100))
(generate_quiz5_test (- num 1))]
[ else (random-num) ])
;; pick random operator
(random-op)
;; third element follows same strategy as the first
(cond
[ (< numprob (random 100))
(generate_quiz5_test (- num 1))]
[ else (random-num) ]))]))
;; generates a flat (non-nested) random expression
(define (quiz5_random_expression )
(list
(random-num)
(random-op)
(random-num)))
;; generates 1 or -1 randomly (used to generate random numbers that can't be 0)
(define (randomsign)
(cond
[(even? (random 2)) 1]
[ else -1]))
;; avoid zero (so we don't divide by 0!)
(define (random-num)
(* (randomsign) (+ 1 (random 500))))
;; pick an operator randomly
(define (random-op)
(list-select '(plus minus times div) (random 4)))
;; used to pick random operator from list
(define (list-select alist pos)
(cond
[(empty? alist) (error 'list-select "Problem selecting an operator")]
[(= 0 pos) (first alist)]
[ else
(list-select (rest alist) (- pos 1))]))
;;
;;
;; main testing function - runs both interp-dave and interp on an
;; expression and compares the results.
(define (quiz5-runtest exp)
(= (interp-dave exp)
(interp exp)))
;; result of this should be 10 trues
(quiz5-runtest (generate_quiz5_test 1))
(quiz5-runtest (generate_quiz5_test 2))
(quiz5-runtest (generate_quiz5_test 3))
(quiz5-runtest (generate_quiz5_test 4))
(quiz5-runtest (generate_quiz5_test 5))
(quiz5-runtest (generate_quiz5_test 6))
(quiz5-runtest (generate_quiz5_test 7))
(quiz5-runtest (generate_quiz5_test 8))
(quiz5-runtest (generate_quiz5_test 9))
(quiz5-runtest (generate_quiz5_test 10))
;; make sure they check the operator (should generate an error)
(interp '(4 blah 22))