Thursday, 22 April 2010

Using LET in LISP

Today we're looking at using LET, but firstly let's look at the answer to our last Lisp tutorial: Write a function called MY-COMPARE using COND that will take two numbers as input and return one of these statements as appropriate:

THE FIRST NUMBER IS LARGER
THE SECOND NUMBER IS LARGER
THE TWO NUMBERS ARE EQUAL
(defun my-compare (x y)
    (cond ((> x y) '(the first number is larger))
          ((< x y) '(the second number is larger))
           (t '(the two numbers are equal))))

Using Let in Lisp
Let creates a local variable: a variable that is only valid inside the function. One common use is to avoid performing the same function over and over again. For example if we need the square of a number several times, we could calculate it once and give it a name rather than calculating it every time:
(defun my-square (x)
  (let ((the-square (* x x)))
   (list 'the 'square 'of x ’is the-square x 'multiplied 'by x 'is the-square)))
One of the best ways to learn is to look at lots of examples. Here's another example that uses LET and calculates the average of two numbers:
(defun average (x y)
       (let ((sum (+ x y)))
           (list x y ’average ’is (/ sum 2.0))))

So far our examples have only used one local variable, we can use LET to specify multiple local variables:
(defun sum-and-difference (x y)
                 (let ((sum (+ x y))
                   (difference (- x y)))
                   (list 'the 'sum 'of x 'and y 'is sum 'the 'difference 'is difference)))

This Lisp let example asks the user to enter a number and uses the NUMBERP predicate to check that what has been entered is a number. If the answer is a number it returns val (which is the number), if NUMBERP returns NIL then the asknumber function is called again.
(defun ask-number ()
  (format t "Please enter a number. ")
  (let ((val (read)))
    (if (numberp val)
        val
        (ask-number)))) 

Here is the general form of LET in Lisp:
(LET ((var-1 value-1)

       (var-2 value-2)

...

       (var-n value-n))

  body)

LET* in Lisp
The LET* creates the local variables one at a time rather than all at once. This means that one local variable can refer to another.

(defun price-change (old new)
  (let* ((diff (- new old))
   (proportion (/ diff old))
   (percentage (* proportion 100.0)))
   (list ’widgets ’changed ’by percentage ’percent))) 

Summary
Using LET and LET* functions in Lisp allow us to create local variables.

Today's Lisp Challenge
Write a Lisp function called GUESS, where you try and guess the number thrown by a dice, this will have several parts.This function will randomly choose from 6 possibilities. You call the function with your guess of 1, 2, 3, 4 5 or 6, the function randomly chooses 6 choices and tells you if your guess was right or wrong.

There are several steps to solving this problem. Any time you have a programming challenge with several steps, break it down into the individual tasks and get these working one by one. Make divide and conquer your programming mantra!

1. The RANDOM function in Lisp returns a random number between 0 and n-1. For example
(random 2) returns one of two possibilities, either 0 or 1. Try evaluating the RANDOM function in your version of Common Lisp.
2. Start writing your GUESS function, by getting it to return either 0, 1, 2, 3, 4 or 5. Then add 1 to the result to get the numbers one to 6.
3. Use LET  to store this random result as a local variable called dice.
3. Use COND to check whether the guess of matches the result ofour local variable dice.
4. If the guess is right return: YOU GUESSED RIGHT IT WAS [put the local variable dice here]
5. If the guess was wrong return: YOU GUESSED WRONG IT WAS [put the local variable dice here]
There are a few steps involved in this, get them working one by one and check back tomorrow for the answer and more programming Lisp tutorials.