Solutions to exercises from week 3

;;; implement own version of not
(defun my-not (anything)
  (if anything
      nil
    t))

;;; function of two numbers - return the smaller
(defun smaller-of-two (first-number second-number)
  (if (< first-number second-number)
      first-number
    second-number))

;;; function of three numbers - return the smallest
(defun smallest-of-three (first-number second-number third-number)
  (if (and (< first-number second-number) (< first-number third-number))
      first-number
    (if (< second-number third-number)
        second-number
      third-number)))

;;; same again, but this version is more readable
(defun smallest-of-three (first-number second-number third-number)
  (smaller-of-two (smaller-of-two first-number smaller-of-two) third-number))

;;; reverse the function fahrenheit-to-celsius
(defun celsius-to-fahrenheit ()
  (format t "~&Please give a value in degrees C: ")
  (let* ((celsius (read))
         (fahrenheit (float (+ (* celsius 9/5) 32))))
    (format t "~&~a degrees C is ~a degrees F.~&" celsius fahrenheit)))

;;; (and foo bar) transforms into (if foo bar nil)
(defun transform-and-with-two-args (form)
  (let* ((first-subform (second form)) ; the first subform was the symbol AND
         (second-subform (third form)))
    (list 'if first-subform second-subform nil)))

;;; (and foo bar baz) transforms into (if foo (if bar baz nil) nil)
(defun transform-and-with-three-args (form)
  (let* ((first-subform (second form)) ; the first subform was the symbol AND
         (second-subform (third form))
         (third-subform (fourth form)))
    (list 'if
          first-subform
          (list 'if second-subform third-subform nil)
          nil)))
 

#|
When considering transformation of (or foo bar) we have to be a
little bit careful.

Consider

   (defun ask-for-help-and-return-t ()
     (format t "Help!")
     t)

   (or (ask-for-help-and-return-t) nil)

Transforming (or foo bar) into
   (if foo
       foo
     bar)
would lead to double trouble.

Hint: use let* ...
|#

;;; (or foo bar) transforms into
#|
(let* ((foo-evaluated foo))
  (if foo-evaluated
      foo-evaluated
    bar))
|#
(defun transform-or-with-two-args (form)
  (let* ((first-subform (second form))
         (second-subform (third form)))
    (list 'let*
          (list (list 'first-evaluated first-subform))
          (list 'if 'first-evaluated 'first-evaluated second-subform))))
 

;;; (or foo bar baz) transforms into
#|
(let* ((foo-evaluated foo))
  (if foo-evaluated
      foo-evaluated
    (let* ((bar-evaluated bar))
      (if bar-evaluated
          bar-evaluated
        baz))))
|#

;;; this is getting really revolting. there has to be a better way
;;; (and, indeed, there is)
(defun transform-or-with-three-args (form)
  (let* ((first-subform (second form))
         (second-subform (third form))
         (third-subform (fourth form)))
    (list 'let*
          (list (list 'first-evaluated first-subform))
          (list 'if
                'first-evaluated
                'first-evaluated
                (list 'let*
                      (list (list 'second-evaluated second-subform))
                      (list 'if
                            'second-evaluated
                            'second-evaluated
                            third-subform))))))
 
 

 If you have tried the exercises, looked at the solutions and still do not understand what's going on, I am available for consultation at the times advertised on my office door. Bring your code with you in BOTH the following forms:

Nick Levine
                                                                               last modified 2000-10-17
                                                         Copyright (C) Nick Levine 1999. All rights reserved.
$Id: //info.ravenbrook.com/user/ndl/lisp/declarative/lectures/solutions/solutions-3.html#2 $