Lisp Books

Sunday 25 April 2010

Using AND NOT and OR in Lisp

Today's Lisp tutorial looks at using AND NOT and OR in Lisp, but firstly let's have a look at the answer to the challenge set in our last Lisp tutorial Using LET in Lisp:

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.

(defun guess (n)
  (let ((dice (+ 1 (random 6))))
    (cond ((equalp dice n )  (list  'you 'guessed 'right 'it 'was dice))
          (t (list 'you 'guessed 'wrong 'it 'was dice)))))

The NOT Predicate in Lisp
We've looked at predicates in Lisp in a previous Lisp tutorial post. Predicates return T or  NIL if the statement is true or false. In Lisp T is true and NIL is false. Using NOT turns T into NIL and NIL into T.

For example using the ZEROP predicate we can test if the number is zero:
(zerop 4)
NIL



(zerop 0)
T


Using NOT we can check to see if a number is not zero:
(not (zerop 4))
T

(not (zerop 0))
NIL

The AND Predicate in Lisp
The AND Predicate in Lisp takes two inputs, both of these must be true for it to evaluate and return T otherwise it returns NIL.
(and (> 6 4) (< 1 3))
T

Here only one of our predicates is true:
(and (numberp 6) (equalp 1 9))
NIL

The OR Predicate in Lisp
The OR Predicate in Lisp returns T if either one or both arguments are true:
(or (numberp 6) (equalp 1 9))
T

(or (> 7 6) (equalp 1 1))
T

Today's Lisp Challenge
Write a function called BETWEEN that takes 3 input arguments N, MIN and MAX. This function tests to see if N is between MIN and MAX.

Subscribe to Programming Lisp Tutorial Blog and check back to see the solution!

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.

Saturday 17 April 2010

Using COND in Common Lisp

Our last post looked at IF THEN statements using the IF function in Lisp. Here's the answer to the challenge set in that post, to write a MY-ABSOLUTE function using an IF function:
(defun my-absolute (x)
              (if (>= x 0) x
                (* -1 x)))

COND
It's possible to use multiple IF functions but if you have lots of things to test it can be more convenient to use a COND function.

COND is a conditional function. It consists of any number of
test and consequent clauses.

(COND (first-test first-consequent)
(second-test second-consequent)
....
(last-test last-consequent))

COND works by progressing through each clause in turn. If the test part is true, COND evaluates the consequent part and returns its value, it does not evaluate any further clauses.

If the test evaluates to NIL (false), COND jumps to the next clause. If all clauses are false, COND returns NIL.
Here's an example COND function:

(defun what-is (x)
  (cond ((equal x ’apple) ’fruit)
    ((equal x ’asparagus) ’vegetable)
    ((equal x ’pork-chop) ’meat)
    (t ’unknown)))

As shown in the example above, it's useful to put a T as the last COND clause. This allows you to return a value or perform another task if all of the preceeding clauses are false.

Today's Challenge:
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

Monday 12 April 2010

If.. then.. else..

Previously we looked at using a predicates to test whether something was TRUE or FALSE, on in Lisp T or NIL:


(oddp 5)
T

Predicates can form part of an IF THEN statement: if something is true then do something.
The IF function takes three arguments: a test, a true part, and a
false part.

For example, using the ODDP function to test if a number is odd and then returning a statement|:

(if (oddp 3) '(the number is odd) '(the number is even))
(THE NUMBER IS ODD)

(if (oddp 4) '(the number is odd) '(the number is even))
(THE NUMBER IS EVEN)

As well as returning simple statements as in the above example, we can also get Lisp to perform further functions is a test is T or nil. This function for example:
  • takes a single number (n) as its input argument.
  • tests to see if a number is odd using the ODDP function,
  • if the number is odd we add 1 to it to make it even,
  • if the ODDP test returns NIL we simply return our original odd number.

;make odd
(defun make-odd (n)
  (if (evenp n) ; the test
      (+ 1 n) ;the true statement
    n)) ; the false statement

Today's Challenge
Write a function in Lisp called MY-ABSOLUTE that returns the absolute value of a number. Absolute values are always non-negative. For negative numbers the absolute value multiply the number by -1; for zero and positive numbers the absolute value is the number itself.

Remember the IF function takes three arguments:
  • a test
  • a true part, and a
  • false part
We'll post the answer in our next http://programminglisp.blogspot.com/ blogpost.

Monday 5 April 2010

Lists in Lisp


Lists are are one of Lisp's most flexible and powerful data types. Here are some examples of lists:
(red orange yellow green blue indigo violet)
(10 green bottles)
(9 18 27 36 45 54 63 72 81 90 99 108)
(thisisalist)
((a)(list of) (lists))

To get the length of a list, we can use the LENGTH function. We have to put the quote mark ' in front of each word here, otherwise Lisp would try to evaluate or understand what we mean:

length '(red orange yellow green blue indigo violet))
7

(length '(10 green bottles))
3

(length '(9 18 27 36 45 54 63 72 81 90 99 108))
12

(length '(thisisalist))
1

(length '((a)(list of) (lists)))
3

As you can see from the final example, lists can contain other lists. The elements of the list are the things that appear inside only one level of parentheses, so in the final example the LENGTH function returns 3 because there are only 3 elements to the list:

(a)
(list of)
(lists)


As we saw briefly in the first steps with Lisp post we can extract individual elements from lists using these functions:


(first '(a b c d e))
A

(second '(a b c d e))
B

(third '(a b c d e))
C

(rest '(a b c d e))
(B C D E)

(last '(a b c d e))
(E) 

(first (first '((a)(list of) (lists))))
A

Creating a new list is very easy using the LIST function:
(list 'banana)
(banana) 

(list 'water 'malt 'hops 'yeast)
(WATER MALT HOPS YEAST)


Again we have to put the quote mark ' in front of each word here, otherwise Lisp would try to evaluate or understand what we mean by water, malt, hops and yeast i.e. had we assigned values to these.

We'll look more at using, creating and extracting data from lists in future posts.