Showing posts with label LISP Tutorial. Show all posts
Showing posts with label LISP Tutorial. Show all posts

Friday, 13 June 2014

LISP -Common Lisp Object System (CLOS)

Filled under:

Post By: Hanan Mannan
Contact Number: Pak (+92)-321-59-95-634
-------------------------------------------------------

LISP -Common Lisp Object System (CLOS)

Common LISP predated the advance of object-oriented programming by couple of decades. However, it object-orientation was incorporated into it at a later stage.

Defining Classes

The defclass macro allows creating user-defined classes. It establishes a class as a data type. It has the following syntax:
(DEFCLASS class-name (superclass-name*)
  (slot-description*)
  class-option*)
The slots are variables that store data, or fields.
A slot-description has the form (slot-name slot-option*), where each option is a keyword followed by a name, expression and other options. Most commonly used slot options are:
  • :accessor function-name
  • :initform expression
  • :initarg symbol
For example, let us define a Box class, with three slots length, breadth, and height.
(defclass Box () 
(length 
breadth 
height))

Providing Access and Read/Write Control to a Slot

Unless the slots have values that can be accessed, read or written to, classes are pretty useless.
You can specify accessors for each slot when you define a class. For example, take our Box class:
(defclass Box ()
  ((length :accessor length)
   (breadth :accessor breadth)
   (height :accessor height)))
You can also specify separate accessor names for reading and writing a slot.
(defclass Box ()
    ((length :reader get-length :writer set-length)
     (breadth :reader get-breadth :writer set-breadth)
     (height :reader get-height :writer set-height)))

Creating Instance of a Class

The generic function make-instance creates and returns a new instance of a class.
It has the following syntax:
(make-instance class {initarg value}*)
Example
Let us create a Box class, with three slots, length, breadth and height. We will use three slot accessors to set the values in these fields.
Create a new source code file named main.lisp and type the following code in it:
(defclass box ()
  ((length :accessor box-length)
   (breadth :accessor box-breadth)
   (height :accessor box-height)))
(setf item (make-instance 'box))
(setf (box-length item) 10)
(setf (box-breadth item) 10)
(setf (box-height item) 5)
(format t "Length of the Box is ~d~%" (box-length item))
(format t "Breadth of the Box is ~d~%" (box-breadth item))
(format t "Height of the Box is ~d~%" (box-height item))
When you execute the code, it returns the following result:
Length of the Box is 10
Breadth of the Box is 10
Height of the Box is 5

Defining a Class Method

The defmethod macro allows you to define a method inside the class. The following example extends our Box class to include a method named volume.
Create a new source code file named main.lisp and type the following code in it:
(defclass box ()
  ((length :accessor box-length)
   (breadth :accessor box-breadth)
   (height :accessor box-height)
   (volume :reader volume)))

; method calculating volume   

(defmethod volume ((object box))
  (* (box-length object) (box-breadth object)(box-height object)))

 ;setting the values 

(setf item (make-instance 'box))
(setf (box-length item) 10)
(setf (box-breadth item) 10)
(setf (box-height item) 5)

; displaying values

(format t "Length of the Box is ~d~%" (box-length item))
(format t "Breadth of the Box is ~d~%" (box-breadth item))
(format t "Height of the Box is ~d~%" (box-height item))
(format t "Volume of the Box is ~d~%" (volume item))
When you execute the code, it returns the following result:
Length of the Box is 10
Breadth of the Box is 10
Height of the Box is 5
Volume of the Box is 500

Inheritance

LISP allows you to define an object in terms of another object. This is called inheritance. You can create a derived class by adding features that are new or different. The derived class inherits the functionalities of the parent class.
The following example explains this:
Example
Create a new source code file named main.lisp and type the following code in it:
(defclass box ()
  ((length :accessor box-length)
   (breadth :accessor box-breadth)
   (height :accessor box-height)
   (volume :reader volume)))
; method calculating volume   
(defmethod volume ((object box))
  (* (box-length object) (box-breadth object)(box-height object)))
  
;wooden-box class inherits the box class  
(defclass wooden-box (box)
((price :accessor box-price)))

 ;setting the values 
(setf item (make-instance 'wooden-box))
(setf (box-length item) 10)
(setf (box-breadth item) 10)
(setf (box-height item) 5)
(setf (box-price item) 1000)

; displaying values

(format t "Length of the Wooden Box is ~d~%" (box-length item))
(format t "Breadth of the Wooden Box is ~d~%" (box-breadth item))
(format t "Height of the Wooden Box is ~d~%" (box-height item))
(format t "Volume of the Wooden Box is ~d~%" (volume item))
(format t "Price of the Wooden Box is ~d~%" (box-price item))
When you execute the code, it returns the following result:
Length of the Wooden Box is 10
Breadth of the Wooden Box is 10
Height of the Wooden Box is 5
Volume of the Wooden Box is 500
Price of the Wooden Box is 1000

Posted By MIrza Abdul Hannan2:18:00 am

LISP - Error Handling

Filled under:

Post By: Hanan Mannan
Contact Number: Pak (+92)-321-59-95-634
-------------------------------------------------------

LISP - Error Handling

Object Oriented Error Handling - Condition System in LISP

In Common LISP terminology, exceptions are called conditions.
In fact, conditions are more general than exceptions in traditional programming languages, because acondition represents any occurrence, error, or not, which might affect various levels of function call stack.
Condition handling mechanism in LISP, handles such situations in such a way that conditions are used to signal warning (say by printing an warning) while the upper level code on the call stack can continue its work.
The condition handling system in LISP has three parts:
  • Signalling a condition
  • Handling the condition
  • Restart the process

Handling a Condition

Let us take up an example of handling a condition arising out of divide by zero condition, to explain the concepts here.
You need to take the following steps for handling a condition:
  1. Define the Condition - "A condition is an object whose class indicates the general nature of the condition and whose instance data carries information about the details of the particular circumstances that lead to the condition being signalled".
    The define-condition macro is used for defining a condition, which has the following syntax:
    (define-condition condition-name (error)
      ((text :initarg :text :reader text)))
    New condition objects are created with MAKE-CONDITION macro, which initializes the slots of the new condition based on the :initargs argument.
    In our example, the following code defines the condition:
    (define-condition on-division-by-zero (error)
       ((message :initarg :message :reader message)))
    
  2. Writing the Handlers - a condition handler is a code that are used for handling the condition signalled thereon. It is generally written in one of the higher level functions that call the erring function. When a condition is signalled, the signalling mechanism searches for an appropriate handler based on the condition's class.
    Each handler consists of:
    • Type specifier, that indicates the type of condition it can handle
    • A function that takes a single argument, the condition
    When a condition is signalled, the signalling mechanism finds the most recently established handler that is compatible with the condition type and calls its function.
    The macro handler-case establishes a condition handler. The basic form of a handler-case :
    (handler-case expression
      error-clause*)
    Where, each error clause is of the form:
    condition-type ([var]) code)
  3. Restarting Phase
    This is the code that actually recovers your program from errors, and condition handlers can then handle a condition by invoking an appropriate restart. The restart code is generally place in middle-level or low-level functions and the condition handlers are placed into the upper levels of the application.
    The handler-bind macro allows you to provide a restart function, and allows you to continue at the lower level functions without unwinding the function call stack. In other words, the flow of control will still be in the lower level function.
    The basic form of handler-bind is as follows:
    (handler-bind (binding*) form*)
    Where each binding is a list of the following:
    • a condition type
    • a handler function of one argument
    The invoke-restart macro finds and invokes the most recently bound restart function with the specified name as argument.
    You can have multiple restarts.
Example
In this example, we demonstrate the above concepts by writing a function named division-function, which will create an error condition if the divisor argument is zero. We have three anonymous functions that provide three ways to come out of it - by returning a value 1, by sending a divisor 2 and recalculating, or by returning 1.
Create a new source code file named main.lisp and type the following code in it:
(define-condition on-division-by-zero (error)
   ((message :initarg :message :reader message)))
   
(defun handle-infinity ()
   (restart-case
       (let ((result 0))
         (setf result (division-function 10 0))
         (format t "Value: ~a~%" result))
     (just-continue () nil)))
     
 (defun division-function (value1 value2)
   (restart-case
       (if (/= value2 0)
           (/ value1 value2)
           (error 'on-division-by-zero :message "denominator is zero"))

     (return-zero () 0)
     (return-value (r) r)
     (recalc-using (d) (division-function value1 d))))

 (defun high-level-code ()
   (handler-bind
       ((on-division-by-zero
         #'(lambda (c)
             (format t "error signaled: ~a~%" (message c))
             (invoke-restart 'return-zero)))
     (handle-infinity))))

   (handler-bind
       ((on-division-by-zero
         #'(lambda (c)
             (format t "error signaled: ~a~%" (message c))
             (invoke-restart 'return-value 1))))
     (handle-infinity))

   (handler-bind
       ((on-division-by-zero
         #'(lambda (c)
             (format t "error signaled: ~a~%" (message c))
             (invoke-restart 'recalc-using 2))))
     (handle-infinity))

   (handler-bind
       ((on-division-by-zero
         #'(lambda (c)
             (format t "error signaled: ~a~%" (message c))
             (invoke-restart 'just-continue))))
     (handle-infinity))

   (format t "Done."))
When you execute the code, it returns the following result:
error signaled: denominator is zero
Value: 1
error signaled: denominator is zero
Value: 5
error signaled: denominator is zero
Done.
Apart from the 'Condition System', as discussed above, Common LISP also provides various functions that may be called for signalling an error. Handling of an error, when signalled, is however, implementation-dependent.

Error Signalling Functions in LISP

The following table provides commonly used functions signalling warnings, breaks, non-fatal and fatal errors.
The user program specifies an error message (a string). The functions process this message and may/may not display it to the user.
The error messages should be constructed by applying the format function, should not contain a newline character at either the beginning or end, and need not indicate error, as the LISP system will take care of these according to its preferred style.
SL No.Functions and Descriptions
1
error format-string &rest args
It signals a fatal error. It is impossible to continue from this kind of error; thus error will never return to its caller.
2
cerror continue-format-string error-format-string &rest args
It signals an error and enters the debugger. However, it allows the program to be continued from the debugger after resolving the error.
3
warn format-string &rest args
it prints an error message but normally doesn't go into the debugger
4
break &optional format-string &rest args
It prints the message and goes directly into the debugger, without allowing any possibility of interception by programmed error-handling facilities
Example
In this example, the factorial function calculates factorial of a number; however, if the argument is negative, it raises an error condition.
Create a new source code file named main.lisp and type the following code in it:
(defun factorial (x)
   (cond ((or (not (typep x 'integer)) (minusp x))
          (error "~S is a negative number." x))
         ((zerop x) 1)
         (t (* x (factorial (- x 1))))))
         
(write(factorial 5))
(terpri)
(write(factorial -1))
When you execute the code, it returns the following result:
120
*** - -1 is a negative number.

Posted By MIrza Abdul Hannan2:17:00 am

LISP - Packages

Filled under:

Post By: Hanan Mannan
Contact Number: Pak (+92)-321-59-95-634
-------------------------------------------------------

LISP - Packages

In general term of programming languages, a package is designed for providing a way to keep one set of names separate from another. The symbols declared in one package will not conflict with the same symbols declared in another. This way packages reduce the naming conflicts between independent code modules.
The LISP reader maintains a table of all the symbols it has found. When it finds a new character sequence, it creates a new symbol and stores in the symbol table. This table is called a package.
The current package is referred by the special variable *package*.
There are two predefined packages in LISP:
  • common-lisp - it contains symbols for all the functions and variables defined.
  • common-lisp-user - it uses the common-lisp package and all other packages with editing and debugging tools; it is called cl-user in short

Package Functions in LISP

The following table provides most commonly used functions used for creating, using and manipulating packages:
SL NoFunctions and Descriptions
1
make-package package-name &key :nicknames :use
It creates and returns a new package with the specified package name.
2
in-package package-name &key :nicknames :use
Makes the package current.
3
in-package name
This macro causes *package* to be set to the package named name, which must be a symbol or string.
4
find-package name
It searches for a package. The package with that name or nickname is returned; if no such package exists, find-package returns nil
5
rename-package package new-name &optional new-nicknames
it renames a package.
6
list-all-packages
This function returns a list of all packages that currently exist in the Lisp system.
7
delete-package package
it deletes a package

Creating a LISP Package

The defpackage function is used for creating an user defined package. It has the following syntax:
defpackage :package-name
  (:use :common-lisp ...)
  (:export :symbol1 :symbol2 ...))
Where,
  • package-name is the name of the package.
  • The :use keyword specifies the packages that this package needs, i.e., packages that define functions used by code in this package.
  • The :export keyword specifies the symbols that are external in this package.
The make-package function is also used for creating a package. The syntax for this function is:
make-package package-name &key :nicknames :use
the arguments and keywords has same meaning as before.

Using a Package

Once you have created a package, you can use the code in this package, by making it the current package. The in-package macro makes a package current in the environment.
Example
Create a new source code file named main.lisp and type the following code in it:
(make-package :tom)
(make-package :dick)
(make-package :harry)
(in-package tom)
(defun hello () 
(write-line "Hello! This is Tom's H.M.R.A Group of Engineers"))
(hello)
(in-package dick)
(defun hello () 
(write-line "Hello! This is Dick's H.M.R.A Group of Engineers"))
(hello)
(in-package harry)
(defun hello () 
(write-line "Hello! This is Harry's H.M.R.A Group of Engineers"))
(hello)
(in-package tom)
(hello)
(in-package dick)
(hello)
(in-package harry)
(hello)
When you execute the code, it returns the following result:
Hello! This is Tom's H.M.R.A Group of Engineers
Hello! This is Dick's H.M.R.A Group of Engineers
Hello! This is Harry's H.M.R.A Group of Engineers

Deleting a Package

The delete-package macro allows you to delete a package. The following example demonstrates this:
Example
Create a new source code file named main.lisp and type the following code in it:
(make-package :tom)
(make-package :dick)
(make-package :harry)
(in-package tom)
(defun hello () 
(write-line "Hello! This is Tom's H.M.R.A Group of Engineers"))
(in-package dick)
(defun hello () 
(write-line "Hello! This is Dick's H.M.R.A Group of Engineers"))
(in-package harry)
(defun hello () 
(write-line "Hello! This is Harry's H.M.R.A Group of Engineers"))
(in-package tom)
(hello)
(in-package dick)
(hello)
(in-package harry)
(hello)
(delete-package tom)
(in-package tom)
(hello)
When you execute the code, it returns the following result:
Hello! This is Tom's H.M.R.A Group of Engineers
Hello! This is Dick's H.M.R.A Group of Engineers
Hello! This is Harry's H.M.R.A Group of Engineers
*** - EVAL: variable TOM has no value

Posted By MIrza Abdul Hannan2:14:00 am