; hw5.lisp ; CS 381 homework 5 ; Jacob Lundberg ; MY-DIRECT-EVAL just evaluates whatever it's passed. ; Arguments should be _flat_ like (MY-DIRECT-EVAL + 1 2 3). ; Result is like (eval '(func1 item item ...)). (defmacro MY-DIRECT-EVAL (func1 &rest items) (cons func1 items) ) ; MY-FUNC-EVAL applies a function to a list (!) using funcall. (defun MY-FUNC-EVAL (func1 list1) (MY-DIRECT-EVAL funcall func1 list1) ) ; MY-MAPAPPEND maps its input through a function and returns a simple list. (defun MY-MAPAPPEND (func1 list1) (cond ((null list1) nil) ; this case is for initial call only ((null (cdr list1)) (MY-FUNC-EVAL func1 (car list1))) ; end of list (T (append (MY-FUNC-EVAL func1 (car list1)) ; evaluate element (MY-MAPAPPEND func1 (cdr list1)))) ; process the rest ) ) ; MY-CHECK-SET-EVAL bridges back from MY-CHECK-LIST-EVAL to MY-CHECK-EVAL. ; This makes several-level testing work. (defun MY-CHECK-SET-EVAL (list1) ; since this is a validity check, we may short-circuit it (cond ((null list1) nil) ((null (car list1)) (MY-CHECK-SET-EVAL (cdr list1))) ((MY-CHECK-EVAL (car list1))) ; short-circuit (T (MY-CHECK-SET-EVAL (cdr list1))) ) ) ; MY-CHECK-LIST-EVAL checks a list for evaluability. (defun MY-CHECK-LIST-EVAL (list1) (cond ((not (symbolp (car list1))) "List starts with non-symbol.") ((not (fboundp (car list1))) "No function binding.") ((not (null (cdr list1))) (MY-CHECK-SET-EVAL (cdr list1))) (T nil) ) ) ; MY-CHECK-EVAL tests the safety of evaluating something. ; If the list is unsafe, an error string is returned. ; If the list is safe, nil is returned. (defun MY-CHECK-EVAL (list1) (cond ((null list1) nil) ; null list ((numberp list1) nil) ; number ((characterp list1) nil) ; character ((stringp list1) nil) ; string ((symbolp list1) (if (boundp list1) nil "No value binding exists.")) ((listp list1) (MY-CHECK-LIST-EVAL list1)) ; list, special case (T "None of the five eval methods are applicable!") ; unlikely ) ) ; MY-CALC-SET-EVAL bridges back from MY-CALC-LIST-EVAL to MY-CALC-EVAL. ; This makes several-level evaluation work. (defun MY-CALC-SET-EVAL (list1) (cond ((null list1) nil) ; passing in all nil might be trouble here (T (cons (MY-CALC-EVAL (car list1)) (MY-CALC-SET-EVAL (cdr list1)))) ) ) ; MY-CALC-LIST-EVAL evaluates a list. (defun MY-CALC-LIST-EVAL (list1) (apply (car list1) (MY-CALC-SET-EVAL (cdr list1))) ) ; MY-CALC-EVAL calculates the return value of evaluating something. (defun MY-CALC-EVAL (list1) (cond ((null list1) nil) ; null list, convert () to nil ((numberp list1) list1) ; number ((characterp list1) list1) ; character ((stringp list1) list1) ; string ((symbolp list1) (symbol-value list1)) ; stand-alone symbol ((listp list1) (MY-CALC-LIST-EVAL list1)) ; list, special case (T nil) ; we have guaranteed above never to reach this case ) ) ; MY-EVAL tries to implement a "crash-proofed" evaluation sequence. (defun MY-EVAL (list1) ; scan for validity, if bad return error, otherwise return result ; not sure if I'm allowed to use eval here so I haven't ... ; since I don't use eval, certain input cases may escape (cond ((MY-CHECK-EVAL list1)) (T (MY-CALC-EVAL list1))) ) ; COMPOSE-WORK composes the result for COMPOSE. (defun COMPOSE-WORK (funcs) (cond ((null funcs) nil) ((null (cdr funcs)) `(lambda (n) ,`(,(car funcs) n))) (T `(lambda (n) ,`(,(COMPOSE-WORK (cdr funcs)) ,`(,(car funcs) n)))) ) ) ; COMPOSE takes one+ single arg funcs and returns the exec'able composition. (defun COMPOSE (&rest funcs) (COMPOSE-WORK (reverse funcs)) ; let the wrapped function fo the work )