; Brian Alliet ; Programming Language Theory ; 4005-710-01 ; Copyright 2005 Brian Alliet ; Part A) ; The following expression evaluates to itself. ; ((lambda (x) (cons x (cons (cons 'quote (cons x '())) '()))) '(lambda (x) (cons x (cons (cons 'quote (cons x '())) '())))) (define quine ((lambda (x) (cons x (cons (cons 'quote (cons x '())) '()))) '(lambda (x) (cons x (cons (cons 'quote (cons x '())) '())))) ) ; This is the curry* function ; When given arguments it curry*'s another lambda that adds our arguments ; back in front before actually applying the function (define (curry* f) (lambda args1 (if (null? args1) (f) (curry* (lambda args2 (apply f (append args1 args2))))))) ; Part B) ; First we define some syntax rules to make creating objects easier (and generic) ; We could actually do this without syntax rules but using them is more efficient ; To make-object makes an object. Its first argument is a list of (method-name value) pairs ; and its (optional) second argument is a "default" method. If a default is not specified ; an unspecific value is returned when an unknown method is called. (define-syntax make-object (syntax-rules () ((make-object (methods ...)) (make-object (methods ...) (lambda x (if #f #f)))) ((make-object (methods ...) default) (lambda args (if (pair? args) ; If an object is called with one or more argument see if the first is a method ; We use make-object-clauses (described below) to handle checking for and calling ; the method (let ((m (car args)) (margs (cdr args))) (make-object-clauses m margs (apply default args) methods ...)) ; If not, just call the default method (default)))) )) ; make-object-clauses generates a series of if's to check for known methods (specified ; as the arguments after the third). If checks for the method named method_ and if found, ; passes it arguments args. If no match is found failure is returned. (define-syntax make-object-clauses (syntax-rules () ((make-object-clauses method_ args failure) failure) ((make-object-clauses method_ args failure (method value) rest ...) (if (eq? method method_) (apply value args) ; found the method, call it with the args (make-object-clauses method_ args failure rest ...))) ; keep looking )) ; Now, defining the conversion class (which is really a plain old object) is simply a ; matter of calling make-object with our methods (define conversion (make-object ; The 'new method makes a conversion object with the a function in the form ax+b (('new (lambda (b a) (conversion 'new-with-functions (lambda (x) (+ (* a x) b)) (lambda (x) (/ (- x b) a))))) ; 'new-with-functions makes a new conversion object with a given function and its inverse ('new-with-functions (lambda (f inverse) ; The result of the call is a conversion "instance" (make-object ; This has an 'inverse method, which returns a new conversion instance ; with the function inverted (('inverse (lambda () (conversion 'new-with-functions inverse f)))) ; The default method applies the function to all its arguments (lambda args (map f args)))))))) ; We define bindings for new and inverse so we can use those names unquoted (define new 'new) (define inverse 'inverse)