LISP - Guía rápida
John McCarthy inventó LISP en 1958, poco después del desarrollo de FORTRAN. Fue implementado por primera vez por Steve Russell en una computadora IBM 704.
Es particularmente adecuado para programas de Inteligencia Artificial, ya que procesa información simbólica de manera efectiva.
Common Lisp se originó, durante las décadas de 1980 y 1990, en un intento de unificar el trabajo de varios grupos de implementación que fueron sucesores de Maclisp, como ZetaLisp y NIL (New Implementation of Lisp), etc.
Sirve como un lenguaje común, que se puede ampliar fácilmente para una implementación específica.
Los programas escritos en Common LISP no dependen de las características específicas de la máquina, como la longitud de las palabras, etc.
Características de Common LISP
Es independiente de la máquina
Utiliza una metodología de diseño iterativo y una fácil extensibilidad.
Permite actualizar los programas de forma dinámica.
Proporciona depuración de alto nivel.
Proporciona programación avanzada orientada a objetos.
Proporciona un sistema macro conveniente.
Proporciona una amplia variedad de tipos de datos como objetos, estructuras, listas, vectores, matrices ajustables, tablas hash y símbolos.
Está basado en expresiones.
Proporciona un sistema de condiciones orientado a objetos.
Proporciona una biblioteca de E / S completa.
Proporciona amplias estructuras de control.
Aplicaciones integradas en LISP
Grandes aplicaciones exitosas integradas en Lisp.
Emacs
G2
AutoCad
Grabador Igor
Tienda Yahoo
Configuración del entorno local
Si aún está dispuesto a configurar su entorno para el lenguaje de programación Lisp, necesita los siguientes dos softwares disponibles en su computadora, (a) Text Editor y (b) The Lisp Executer.
Editor de texto
Esto se utilizará para escribir su programa. Algunos ejemplos de algunos editores incluyen el Bloc de notas de Windows, el comando de edición del sistema operativo, Brief, Epsilon, EMACS y vim o vi.
El nombre y la versión del editor de texto pueden variar en diferentes sistemas operativos. Por ejemplo, el Bloc de notas se usará en Windows, y vim o vi se pueden usar en Windows, así como en Linux o UNIX.
Los archivos que crea con su editor se denominan archivos fuente y contienen el código fuente del programa. Los archivos de origen de los programas Lisp generalmente se nombran con la extensión ".lisp".
Antes de comenzar a programar, asegúrese de tener un editor de texto en su lugar y de tener suficiente experiencia para escribir un programa de computadora, guardarlo en un archivo y finalmente ejecutarlo.
El Lisp Executer
El código fuente escrito en el archivo fuente es la fuente legible por humanos para su programa. Debe ser "ejecutado", para convertirse en lenguaje de máquina para que su CPU pueda ejecutar el programa según las instrucciones dadas.
Este lenguaje de programación Lisp se utilizará para ejecutar su código fuente en el programa ejecutable final. Supongo que tienes conocimientos básicos sobre un lenguaje de programación.
CLISP es el compilador de arquitectura múltiple GNU Common LISP que se utiliza para configurar LISP en Windows. La versión de Windows emula un entorno Unix usando MingW bajo Windows. El instalador se encarga de esto y agrega automáticamente clisp a la variable PATH de Windows.
Puede obtener el último CLISP para Windows desde aquí: https://sourceforge.net/projects/clisp/files/latest/download
Crea un acceso directo en el menú Inicio de forma predeterminada, para el intérprete línea por línea.
Cómo usar CLISP
Durante la instalación, clisp se agrega automáticamente a su variable PATH si selecciona la opción (RECOMENDADO). Esto significa que simplemente puede abrir una nueva ventana del símbolo del sistema y escribir "clisp" para que aparezca el compilador.
Para ejecutar un archivo * .lisp o * .lsp, simplemente use -
clisp hello.lisp
Las expresiones LISP se denominan expresiones simbólicas o expresiones-s. Las expresiones-s se componen de tres objetos válidos, átomos, listas y cadenas.
Cualquier expresión-s es un programa válido.
Los programas LISP se ejecutan en un interpreter o como compiled code.
El intérprete verifica el código fuente en un ciclo repetido, que también se denomina ciclo de lectura-evaluación-impresión (REPL). Lee el código del programa, lo evalúa e imprime los valores devueltos por el programa.
Un programa simple
Escribamos una expresión-s para encontrar la suma de tres números 7, 9 y 11. Para hacer esto, podemos escribir en la indicación del intérprete.
(+ 7 9 11)
LISP devuelve el resultado:
27
Si desea ejecutar el mismo programa que un código compilado, cree un archivo de código fuente LISP llamado myprog.lisp y escriba el siguiente código en él.
(write (+ 7 9 11))
Cuando hace clic en el botón Ejecutar, o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es:
27
LISP utiliza la notación de prefijo
Es posible que haya notado que LISP usa prefix notation.
En el programa anterior, el símbolo + funciona como el nombre de la función para el proceso de suma de los números.
En notación de prefijo, los operadores se escriben antes de sus operandos. Por ejemplo, la expresión,
a * ( b + c ) / d
se escribirá como -
(/ (* a (+ b c) ) d)
Tomemos otro ejemplo, escribamos código para convertir la temperatura Fahrenheit de 60 o F a la escala centígrada -
La expresión matemática para esta conversión será:
(60 * 9 / 5) + 32
Cree un archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write(+ (* (/ 9 5) 60) 32))
Cuando hace clic en el botón Ejecutar, o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es -
140
Evaluación de programas LISP
La evaluación de los programas LISP tiene dos partes:
Traducción del texto del programa en objetos Lisp por un programa lector
Implementación de la semántica del lenguaje en términos de estos objetos por un programa evaluador
El proceso de evaluación toma los siguientes pasos:
El lector traduce las cadenas de caracteres a objetos LISP o s-expressions.
El evaluador define la sintaxis de Lisp formsque se construyen a partir de expresiones-s. Este segundo nivel de evaluación define una sintaxis que determina qués-expressions son formularios LISP.
El evaluador funciona como una función que toma una forma LISP válida como argumento y devuelve un valor. Esta es la razón por la que ponemos la expresión LISP entre paréntesis, porque estamos enviando la expresión / formulario completo al evaluador como argumentos.
El programa 'Hola mundo'
Aprender un nuevo lenguaje de programación no despega realmente hasta que aprenda a saludar al mundo entero en ese idioma, ¿verdad?
Por lo tanto, cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write-line "Hello World")
(write-line "I am at 'Tutorials Point'! Learning LISP")
Cuando hace clic en el botón Ejecutar, o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es:
Hello World
I am at 'Tutorials Point'! Learning LISP
Bloques de construcción básicos en LISP
Los programas LISP se componen de tres componentes básicos:
- atom
- list
- string
Un atomes un número o una cadena de caracteres contiguos. Incluye números y caracteres especiales.
A continuación se muestran ejemplos de algunos átomos válidos:
hello-from-tutorials-point
name
123008907
*hello*
Block#221
abc123
UN list es una secuencia de átomos y / u otras listas entre paréntesis.
A continuación se muestran ejemplos de algunas listas válidas:
( i am a list)
(a ( a b c) d e fgh)
(father tom ( susan bill joe))
(sun mon tue wed thur fri sat)
( )
UN string es un grupo de caracteres entre comillas dobles.
A continuación se muestran ejemplos de algunas cadenas válidas:
" I am a string"
"a ba c d efg #$%^&!"
"Please enter the following details :"
"Hello from 'Tutorials Point'! "
Agregar comentarios
El símbolo de punto y coma (;) se utiliza para indicar una línea de comentario.
Por ejemplo,
(write-line "Hello World") ; greet the world
; tell them your whereabouts
(write-line "I am at 'Tutorials Point'! Learning LISP")
Cuando hace clic en el botón Ejecutar, o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es:
Hello World
I am at 'Tutorials Point'! Learning LISP
Algunos puntos notables antes de pasar al siguiente
A continuación se presentan algunos de los puntos importantes a tener en cuenta:
Las operaciones numéricas básicas en LISP son +, -, * y /
LISP representa una llamada de función f (x) como (fx), por ejemplo, cos (45) se escribe como cos 45
Las expresiones LISP no distinguen entre mayúsculas y minúsculas, cos 45 o COS 45 son iguales.
LISP intenta evaluar todo, incluidos los argumentos de una función. Solo tres tipos de elementos son constantes y siempre devuelven su propio valor
Numbers
La carta t, eso significa verdad lógica.
El valor nil, que significa falso lógico, así como una lista vacía.
Poco más sobre los formularios LISP
En el capítulo anterior, mencionamos que el proceso de evaluación del código LISP toma los siguientes pasos.
El lector traduce las cadenas de caracteres a objetos LISP o s-expressions.
El evaluador define la sintaxis de Lisp formsque se construyen a partir de expresiones-s. Este segundo nivel de evaluación define una sintaxis que determina qué expresiones-s son formas LISP.
Ahora, un formulario LISP podría ser.
- Un átomo
- Una lista vacía o no
- Cualquier lista que tenga un símbolo como primer elemento
El evaluador funciona como una función que toma una forma LISP válida como argumento y devuelve un valor. Esta es la razón por la que ponemos elLISP expression in parenthesis, porque estamos enviando la expresión / formulario completo al evaluador como argumentos.
Convenciones de nomenclatura en LISP
El nombre o los símbolos pueden constar de cualquier número de caracteres alfanuméricos que no sean espacios en blanco, paréntesis de apertura y cierre, comillas simples y dobles, barra invertida, coma, dos puntos, punto y coma y barra vertical. Para usar estos caracteres en un nombre, debe usar el carácter de escape (\).
Un nombre puede tener dígitos, pero no completamente compuesto de dígitos, porque entonces se leería como un número. De manera similar, un nombre puede tener puntos, pero no puede estar compuesto completamente por puntos.
Uso de comillas simples
LISP evalúa todo, incluidos los argumentos de la función y los miembros de la lista.
A veces, necesitamos tomar los átomos o las listas literalmente y no queremos que sean evaluados o tratados como llamadas a funciones.
Para hacer esto, necesitamos preceder el átomo o la lista con una comilla simple.
El siguiente ejemplo demuestra esto.
Cree un archivo llamado main.lisp y escriba el siguiente código en él.
(write-line "single quote used, it inhibits evaluation")
(write '(* 2 3))
(write-line " ")
(write-line "single quote not used, so expression evaluated")
(write (* 2 3))
Cuando hace clic en el botón Ejecutar, o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es:
single quote used, it inhibits evaluation
(* 2 3)
single quote not used, so expression evaluated
6
En LISP, las variables no se escriben, pero los objetos de datos sí.
Los tipos de datos LISP se pueden clasificar como.
Scalar types - por ejemplo, tipos de números, caracteres, símbolos, etc.
Data structures - por ejemplo, listas, vectores, vectores de bits y cadenas.
Cualquier variable puede tomar cualquier objeto LISP como su valor, a menos que lo haya declarado explícitamente.
Aunque no es necesario especificar un tipo de datos para una variable LISP, sin embargo, ayuda en ciertas expansiones de bucles, en declaraciones de métodos y en algunas otras situaciones que discutiremos en capítulos posteriores.
Los tipos de datos se organizan en una jerarquía. Un tipo de datos es un conjunto de objetos LISP y muchos objetos pueden pertenecer a uno de esos conjuntos.
los typep El predicado se utiliza para encontrar si un objeto pertenece a un tipo específico.
los type-of La función devuelve el tipo de datos de un objeto dado.
Especificadores de tipo en LISP
Los especificadores de tipo son símbolos definidos por el sistema para tipos de datos.
formación | fixnum | paquete | cadena simple |
átomo | flotador | nombre de ruta | vector simple |
bignum | función | estado aleatorio | flotador simple |
poco | tabla de picadillo | proporción | carácter estándar |
vector de bits | entero | racional | corriente |
personaje | palabra clave | readtable | cuerda |
[común] | lista | secuencia | [string-char] |
función-compilada | flotar largo | flotador corto | símbolo |
complejo | cero | byte firmado | t |
contras | nulo | matriz simple | byte sin firmar |
flotador doble | número | vector de bits simple | vector |
Aparte de estos tipos definidos por el sistema, puede crear sus propios tipos de datos. Cuando un tipo de estructura se define usandodefstruct función, el nombre del tipo de estructura se convierte en un símbolo de tipo válido.
Ejemplo 1
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq x 10)
(setq y 34.567)
(setq ch nil)
(setq n 123.78)
(setq bg 11.0e+4)
(setq r 124/2)
(print x)
(print y)
(print n)
(print ch)
(print bg)
(print r)
Cuando hace clic en el botón Ejecutar, o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es:
10
34.567
123.78
NIL
110000.0
62
Ejemplo 2
A continuación, verifiquemos los tipos de variables utilizadas en el ejemplo anterior. Cree un nuevo archivo de código fuente llamado main. lisp y escriba el siguiente código en él.
(defvar x 10)
(defvar y 34.567)
(defvar ch nil)
(defvar n 123.78)
(defvar bg 11.0e+4)
(defvar r 124/2)
(print (type-of x))
(print (type-of y))
(print (type-of n))
(print (type-of ch))
(print (type-of bg))
(print (type-of r))
Cuando hace clic en el botón Ejecutar, o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es:
(INTEGER 0 281474976710655)
SINGLE-FLOAT
SINGLE-FLOAT
NULL
SINGLE-FLOAT
(INTEGER 0 281474976710655)
Las macros le permiten ampliar la sintaxis de LISP estándar.
Técnicamente, una macro es una función que toma una expresión-s como argumentos y devuelve una forma LISP, que luego se evalúa.
Definición de una macro
En LISP, una macro nombrada se define usando otra macro llamada defmacro. La sintaxis para definir una macro es:
(defmacro macro-name (parameter-list))
"Optional documentation string."
body-form
La definición de la macro consiste en el nombre de la macro, una lista de parámetros, una cadena de documentación opcional y un cuerpo de expresiones Lisp que define el trabajo que debe realizar la macro.
Ejemplo
Escribamos una macro simple llamada setTo10, que tomará un número y establecerá su valor en 10.
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(defmacro setTo10(num)
(setq num 10)(print num))
(setq x 25)
(print x)
(setTo10 x)
Cuando hace clic en el botón Ejecutar, o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es:
25
10
En LISP, cada variable está representada por un symbol. El nombre de la variable es el nombre del símbolo y se almacena en la celda de almacenamiento del símbolo.
Variables globales
Las variables globales tienen valores permanentes en todo el sistema LISP y permanecen vigentes hasta que se especifica un nuevo valor.
Las variables globales se declaran generalmente usando el defvar construir.
Por ejemplo
(defvar x 234)
(write x)
Cuando hace clic en el botón Ejecutar, o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es
234
Dado que no hay una declaración de tipo para las variables en LISP, usted especifica directamente un valor para un símbolo con el setq construir.
Por ejemplo
->(setq x 10)
La expresión anterior asigna el valor 10 a la variable x. Puede hacer referencia a la variable utilizando el símbolo en sí como expresión.
los symbol-value La función le permite extraer el valor almacenado en el lugar de almacenamiento de símbolos.
Por ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq x 10)
(setq y 20)
(format t "x = ~2d y = ~2d ~%" x y)
(setq x 100)
(setq y 200)
(format t "x = ~2d y = ~2d" x y)
Cuando hace clic en el botón Ejecutar o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es.
x = 10 y = 20
x = 100 y = 200
Variables locales
Las variables locales se definen dentro de un procedimiento dado. Los parámetros nombrados como argumentos dentro de una definición de función también son variables locales. Las variables locales son accesibles solo dentro de la función respectiva.
Como las variables globales, las variables locales también se pueden crear usando el setq construir.
Hay otras dos construcciones: let y prog para crear variables locales.
La construcción let tiene la siguiente sintaxis.
(let ((var1 val1) (var2 val2).. (varn valn))<s-expressions>)
Donde var1, var2, ..varn son nombres de variables y val1, val2, .. valn son los valores iniciales asignados a las respectivas variables.
Cuando letse ejecuta, a cada variable se le asigna el valor respectivo y finalmente se evalúa la expresión-s . Se devuelve el valor de la última expresión evaluada.
Si no incluye un valor inicial para una variable, se asigna a nil.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(let ((x 'a) (y 'b)(z 'c))
(format t "x = ~a y = ~a z = ~a" x y z))
Cuando hace clic en el botón Ejecutar o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es.
x = A y = B z = C
los prog La construcción también tiene la lista de variables locales como su primer argumento, que es seguido por el cuerpo del prog, y cualquier número de expresiones-s.
los prog la función ejecuta la lista de expresiones-s en secuencia y devuelve nil a menos que encuentre una llamada de función llamada return. Entonces el argumento del return La función se evalúa y devuelve.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(prog ((x '(a b c))(y '(1 2 3))(z '(p q 10)))
(format t "x = ~a y = ~a z = ~a" x y z))
Cuando hace clic en el botón Ejecutar o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es.
x = (A B C) y = (1 2 3) z = (P Q 10)
En LISP, las constantes son variables que nunca cambian sus valores durante la ejecución del programa. Las constantes se declaran utilizando eldefconstant construir.
Ejemplo
El siguiente ejemplo muestra la declaración de un PI constante global y luego el uso de este valor dentro de una función denominada área-círculo que calcula el área de un círculo.
los defun La construcción se usa para definir una función, la veremos en el Functions capítulo.
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(defconstant PI 3.141592)
(defun area-circle(rad)
(terpri)
(format t "Radius: ~5f" rad)
(format t "~%Area: ~10f" (* PI rad rad)))
(area-circle 10)
Cuando hace clic en el botón Ejecutar o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es.
Radius: 10.0
Area: 314.1592
Un operador es un símbolo que le dice al compilador que realice manipulaciones matemáticas o lógicas específicas. LISP permite numerosas operaciones sobre datos, respaldadas por varias funciones, macros y otras construcciones.
Las operaciones permitidas en los datos se pueden clasificar como:
- Operaciones aritmeticas
- Operaciones de comparación
- Operaciones lógicas
- Operaciones bit a bit
Operaciones aritmeticas
La siguiente tabla muestra todos los operadores aritméticos admitidos por LISP. Asumir variableA tiene 10 y variable B sostiene 20 entonces -
Show Examples
Operador | Descripción | Ejemplo |
---|---|---|
+ | Agrega dos operandos | (+ AB) dará 30 |
- | Resta el segundo operando del primero | (- AB) dará -10 |
* | Multiplica ambos operandos | (* AB) dará 200 |
/ | Divide el numerador por el numerador | (/ BA) dará 2 |
mod, rem | Operador de módulo y resto de después de una división entera | (mod BA) dará 0 |
incf | El operador de incrementos aumenta el valor entero por el segundo argumento especificado | (incf A 3) dará 13 |
decf | El operador de decrementos disminuye el valor entero por el segundo argumento especificado | (decf A 4) dará 9 |
Operaciones de comparación
La siguiente tabla muestra todos los operadores relacionales soportados por LISP que compara entre números. Sin embargo, a diferencia de los operadores relacionales en otros lenguajes, los operadores de comparación LISP pueden tomar más de dos operandos y solo funcionan con números.
Asumir variable A tiene 10 y variable B tiene 20, entonces -
Show Examples
Operador | Descripción | Ejemplo |
---|---|---|
= | Comprueba si los valores de los operandos son todos iguales o no, si es así, la condición se convierte en verdadera. | (= AB) no es cierto. |
/ = | Comprueba si los valores de los operandos son todos diferentes o no, si los valores no son iguales, la condición se convierte en verdadera. | (/ = AB) es cierto. |
> | Comprueba si los valores de los operandos disminuyen monótonamente. | (> AB) no es cierto. |
< | Comprueba si los valores de los operandos aumentan monótonamente. | (<AB) es cierto. |
> = | Comprueba si el valor de cualquier operando izquierdo es mayor o igual que el valor del siguiente operando derecho, si es así, la condición se convierte en verdadera. | (> = AB) no es cierto. |
<= | Comprueba si el valor de cualquier operando de la izquierda es menor o igual que el valor de su operando de la derecha, si es así, la condición se convierte en verdadera. | (<= AB) es cierto. |
max | Compara dos o más argumentos y devuelve el valor máximo. | (max AB) devuelve 20 |
min | Compara dos o más argumentos y devuelve el valor mínimo. | (min AB) devuelve 10 |
Operaciones lógicas con valores booleanos
Common LISP proporciona tres operadores lógicos: and, or, y notque opera con valores booleanos. AsumirA tiene valor nulo y B tiene valor 5, entonces -
Show Examples
Operador | Descripción | Ejemplo |
---|---|---|
y | Requiere cualquier número de argumentos. Los argumentos se evalúan de izquierda a derecha. Si todos los argumentos se evalúan como no nulos, se devuelve el valor del último argumento. De lo contrario, se devuelve nil. | (y AB) devolverá NIL. |
o | Requiere cualquier número de argumentos. Los argumentos se evalúan de izquierda a derecha hasta que uno se evalúa como no nulo, en tal caso se devuelve el valor del argumento; de lo contrario, devuelvenil. | (o AB) devolverá 5. |
no | Toma un argumento y regresa t si el argumento se evalúa como nil. | (no A) devolverá T. |
Operaciones bit a bit en números
Los operadores bit a bit trabajan en bits y realizan operaciones bit a bit. Las tablas de verdad para operaciones bit a bit and, or y xor son las siguientes:
Show Examples
pags | q | p y q | po q | p xo q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
Assume if A = 60; and B = 13; now in binary format they will be as follows:
A = 0011 1100
B = 0000 1101
-----------------
A and B = 0000 1100
A or B = 0011 1101
A xor B = 0011 0001
not A = 1100 0011
Los operadores Bitwise admitidos por LISP se enumeran en la siguiente tabla. Asumir variableA tiene 60 y variable B tiene 13, entonces -
Operador | Descripción | Ejemplo |
---|---|---|
logand | Esto devuelve el AND lógico bit a bit de sus argumentos. Si no se proporciona ningún argumento, el resultado es -1, que es una identidad para esta operación. | (logand ab)) dará 12 |
logior | Esto devuelve el OR INCLUSIVO lógico bit a bit de sus argumentos. Si no se proporciona ningún argumento, el resultado es cero, que es una identidad para esta operación. | (logior ab) dará 61 |
logxor | Esto devuelve el OR EXCLUSIVO lógico bit a bit de sus argumentos. Si no se proporciona ningún argumento, el resultado es cero, que es una identidad para esta operación. | (logxor ab) dará 49 |
lognor | Esto devuelve el NO bit a bit de sus argumentos. Si no se proporciona ningún argumento, el resultado es -1, que es una identidad para esta operación. | (lognor ab) dará -62, |
logeqv | Esto devuelve la EQUIVALENCIA lógica bit a bit (también conocida como exclusiva ni) de sus argumentos. Si no se proporciona ningún argumento, el resultado es -1, que es una identidad para esta operación. | (logeqv ab) dará -50 |
Las estructuras de toma de decisiones requieren que el programador especifique una o más condiciones para ser evaluadas o probadas por el programa, junto con una declaración o declaraciones que se ejecutarán si se determina que la condición es verdadera y, opcionalmente, otras declaraciones que se ejecutarán si la condición se determina que es falso.
A continuación se muestra la forma general de una estructura de toma de decisiones típica que se encuentra en la mayoría de los lenguajes de programación:
LISP proporciona los siguientes tipos de constructos para la toma de decisiones. Haga clic en los siguientes enlaces para verificar su detalle.
No Señor. | Construcción y descripción |
---|---|
1 | cond Esta construcción se usa para verificar múltiples cláusulas de acción de prueba. Se puede comparar con las instrucciones if anidadas en otros lenguajes de programación. |
2 | Si El constructo if tiene varias formas. En su forma más simple, va seguida de una cláusula de prueba, una acción de prueba y alguna otra acción o acciones consiguientes. Si la cláusula de prueba se evalúa como verdadera, entonces la acción de prueba se ejecuta; de lo contrario, se evalúa la cláusula consecuente. |
3 | cuando En su forma más simple, va seguida de una cláusula de prueba y una acción de prueba. Si la cláusula de prueba se evalúa como verdadera, entonces la acción de prueba se ejecuta; de lo contrario, se evalúa la cláusula consecuente. |
4 | caso Esta construcción implementa múltiples cláusulas de acción de prueba como la construcción cond. Sin embargo, evalúa un formulario de clave y permite múltiples cláusulas de acción basadas en la evaluación de ese formulario de clave. |
Puede haber una situación en la que necesite ejecutar un bloque de números de código de veces. Una declaración de bucle nos permite ejecutar una declaración o grupo de declaraciones varias veces y, a continuación, se encuentra la forma general de una declaración de bucle en la mayoría de los lenguajes de programación.
LISP proporciona los siguientes tipos de construcciones para manejar los requisitos de bucle. Haga clic en los siguientes enlaces para verificar su detalle.
No Señor. | Construcción y descripción |
---|---|
1 | lazo los loopLa construcción es la forma más simple de iteración proporcionada por LISP. En su forma más simple, le permite ejecutar algunas declaraciones repetidamente hasta que encuentre unareturn declaración. |
2 | bucle para La construcción de bucle for le permite implementar una iteración tipo bucle for como la más común en otros lenguajes. |
3 | hacer La construcción do también se usa para realizar iteraciones usando LISP. Proporciona una forma estructurada de iteración. |
4 | dotimes La construcción dotimes permite realizar un bucle para un número fijo de iteraciones. |
5 | lista de tareas La construcción dolist permite la iteración a través de cada elemento de una lista. |
Salir con gracia de un bloque
los block y return-from le permite salir con gracia de cualquier bloque anidado en caso de cualquier error.
los blockLa función le permite crear un bloque con nombre con un cuerpo compuesto por cero o más declaraciones. La sintaxis es -
(block block-name(
...
...
))
los return-from La función toma un nombre de bloque y un valor de retorno opcional (el predeterminado es nulo).
El siguiente ejemplo demuestra esto:
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él:
(defun demo-function (flag)
(print 'entering-outer-block)
(block outer-block
(print 'entering-inner-block)
(print (block inner-block
(if flag
(return-from outer-block 3)
(return-from inner-block 5)
)
(print 'This-wil--not-be-printed))
)
(print 'left-inner-block)
(print 'leaving-outer-block)
t)
)
(demo-function t)
(terpri)
(demo-function nil)
Cuando hace clic en el botón Ejecutar, o escribe Ctrl + E, LISP lo ejecuta inmediatamente y el resultado devuelto es:
ENTERING-OUTER-BLOCK
ENTERING-INNER-BLOCK
ENTERING-OUTER-BLOCK
ENTERING-INNER-BLOCK
5
LEFT-INNER-BLOCK
LEAVING-OUTER-BLOCK
Una función es un grupo de declaraciones que juntas realizan una tarea.
Puede dividir su código en funciones separadas. La forma de dividir su código entre las diferentes funciones depende de usted, pero lógicamente la división suele ser para que cada función realice una tarea específica.
Definición de funciones en LISP
La macro nombrada defunse utiliza para definir funciones. losdefun macro necesita tres argumentos -
- Nombre de la función
- Parámetros de la función
- Cuerpo de la función
La sintaxis de defun es -
(defun name (parameter-list) "Optional documentation string." body)
Ilustremos el concepto con ejemplos sencillos.
Ejemplo 1
Escribamos una función llamada averagenum que imprima el promedio de cuatro números. Enviaremos estos números como parámetros.
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(defun averagenum (n1 n2 n3 n4)
(/ ( + n1 n2 n3 n4) 4)
)
(write(averagenum 10 20 30 40))
Cuando ejecuta el código, devuelve el siguiente resultado:
25
Ejemplo 2
Definamos y llamemos una función que calcularía el área de un círculo cuando el radio del círculo se da como argumento.
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(defun area-circle(rad)
"Calculates area of a circle with given radius"
(terpri)
(format t "Radius: ~5f" rad)
(format t "~%Area: ~10f" (* 3.141592 rad rad))
)
(area-circle 10)
Cuando ejecuta el código, devuelve el siguiente resultado:
Radius: 10.0
Area: 314.1592
Tenga en cuenta que -
Puede proporcionar una lista vacía como parámetros, lo que significa que la función no acepta argumentos, la lista está vacía, escrita como ().
LISP también permite argumentos opcionales, múltiples y de palabras clave.
La cadena de documentación describe el propósito de la función. Está asociado con el nombre de la función y se puede obtener usando eldocumentation función.
El cuerpo de la función puede constar de cualquier número de expresiones Lisp.
El valor de la última expresión del cuerpo se devuelve como el valor de la función.
También puede devolver un valor de la función usando el return-from operador especial.
Analicemos brevemente los conceptos anteriores. Haga clic en los siguientes enlaces para encontrar detalles:
Parámetros opcionales
Parámetros de descanso
Parámetros de palabras clave
Devolver valores de una función
Funciones lambda
Funciones de mapeo
Los predicados son funciones que prueban sus argumentos para algunas condiciones específicas y devuelven nil si la condición es falsa, o algún valor no nulo si la condición es verdadera.
La siguiente tabla muestra algunos de los predicados más utilizados:
No Señor. | Predicado y descripción |
---|---|
1 | atom Toma un argumento y devuelve t si el argumento es un átomo o nil en caso contrario. |
2 | equal Toma dos argumentos y devuelve t si son estructuralmente iguales o nil de otra manera. |
3 | eq Toma dos argumentos y devuelve t si son los mismos objetos idénticos, compartiendo la misma ubicación de memoria o nil de otra manera. |
4 | eql Toma dos argumentos y devuelve t si los argumentos son eq, o si son números del mismo tipo con el mismo valor, o si son objetos de carácter que representan el mismo carácter, o nil de otra manera. |
5 | evenp Toma un argumento numérico y devuelve t si el argumento es un número par o nil si no. |
6 | oddp Toma un argumento numérico y devuelve t si el argumento es un número impar o nil si no. |
7 | zerop Toma un argumento numérico y devuelve t si el argumento es cero o nil si no. |
8 | null Toma un argumento y regresa t si el argumento se evalúa como nulo, de lo contrario devuelve nil. |
9 | listp Toma un argumento y regresa t si el argumento se evalúa como una lista de lo contrario, devuelve nil. |
10 | greaterp Toma uno o más argumentos y regresa t si hay un solo argumento o los argumentos son sucesivamente más grandes de izquierda a derecha, o nil si no. |
11 | lessp Toma uno o más argumentos y regresa t si hay un solo argumento o los argumentos son sucesivamente más pequeños de izquierda a derecha, o nil si no. |
12 | numberp Toma un argumento y regresa t si el argumento es un número o nil si no. |
13 | symbolp Toma un argumento y regresa t si el argumento es un símbolo, de lo contrario, devuelve nil. |
14 | integerp Toma un argumento y regresa t si el argumento es un número entero, de lo contrario, devuelve nil. |
15 | rationalp Toma un argumento y regresa t si el argumento es un número racional, ya sea una razón o un número, de lo contrario devuelve nil. |
dieciséis | floatp Toma un argumento y regresa t si el argumento es un número de punto flotante, de lo contrario, devuelve nil. |
17 | realp Toma un argumento y regresa t si el argumento es un número real, de lo contrario, devuelve nil. |
18 | complexp Toma un argumento y regresa t si el argumento es un número complejo, de lo contrario, devuelve nil. |
19 | characterp Toma un argumento y regresa t si el argumento es un carácter, de lo contrario, regresa nil. |
20 | stringp Toma un argumento y regresa t si el argumento es un objeto de cadena de lo contrario, devuelve nil. |
21 | arrayp Toma un argumento y regresa t si el argumento es un objeto de matriz, de lo contrario, devuelve nil. |
22 | packagep Toma un argumento y regresa t si el argumento es un paquete, de lo contrario, regresa nil. |
Ejemplo 1
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (atom 'abcd))
(terpri)
(write (equal 'a 'b))
(terpri)
(write (evenp 10))
(terpri)
(write (evenp 7 ))
(terpri)
(write (oddp 7 ))
(terpri)
(write (zerop 0.0000000001))
(terpri)
(write (eq 3 3.0 ))
(terpri)
(write (equal 3 3.0 ))
(terpri)
(write (null nil ))
Cuando ejecuta el código, devuelve el siguiente resultado:
T
NIL
T
NIL
T
NIL
NIL
NIL
T
Ejemplo 2
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(defun factorial (num)
(cond ((zerop num) 1)
(t ( * num (factorial (- num 1))))
)
)
(setq n 6)
(format t "~% Factorial ~d is: ~d" n (factorial n))
Cuando ejecuta el código, devuelve el siguiente resultado:
Factorial 6 is: 720
Common Lisp define varios tipos de números. losnumber El tipo de datos incluye varios tipos de números admitidos por LISP.
Los tipos de números admitidos por LISP son:
- Integers
- Ratios
- Números de punto flotante
- Números complejos
El siguiente diagrama muestra la jerarquía numérica y varios tipos de datos numéricos disponibles en LISP:
Varios tipos numéricos en LISP
La siguiente tabla describe varios datos de tipos de números disponibles en LISP:
No Señor. | Tipo de datos y descripción |
---|---|
1 | fixnum Este tipo de datos representa números enteros que no son demasiado grandes y en su mayoría en el rango de -215 a 215-1 (depende de la máquina) |
2 | bignum Estos son números muy grandes con un tamaño limitado por la cantidad de memoria asignada para LISP, no son números fijos. |
3 | ratio Representa la razón de dos números en forma de numerador / denominador. La función / siempre produce el resultado en proporciones, cuando sus argumentos son números enteros. |
4 | float Representa números no enteros. Hay cuatro tipos de datos flotantes con una precisión creciente. |
5 | complex Representa números complejos, que se indican con #c. Las partes reales e imaginarias pueden ser números de punto flotante o racionales. |
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (/ 1 2))
(terpri)
(write ( + (/ 1 2) (/ 3 4)))
(terpri)
(write ( + #c( 1 2) #c( 3 -4)))
Cuando ejecuta el código, devuelve el siguiente resultado:
1/2
5/4
#C(4 -2)
Funciones numéricas
La siguiente tabla describe algunas funciones numéricas de uso común:
No Señor. | Función descriptiva |
---|---|
1 | +, -, *, / Operaciones aritméticas respectivas |
2 | sin, cos, tan, acos, asin, atan Funciones trigonométricas respectivas. |
3 | sinh, cosh, tanh, acosh, asinh, atanh Funciones hiperbólicas respectivas. |
4 | exp Función de exponenciación. Calcula e x |
5 | expt Función de exponenciación, toma base y potencia ambos. |
6 | sqrt Calcula la raíz cuadrada de un número. |
7 | log Función logarítmica. Si se le da un parámetro, luego calcula su logaritmo natural; de lo contrario, el segundo parámetro se usa como base. |
8 | conjugate Calcula el conjugado complejo de un número. En el caso de un número real, devuelve el número en sí. |
9 | abs Devuelve el valor absoluto (o magnitud) de un número. |
10 | gcd Calcula el máximo común divisor de los números dados. |
11 | lcm Calcula el mínimo común múltiplo de los números dados. |
12 | isqrt Da el mayor número entero menor o igual a la raíz cuadrada exacta de un número natural dado. |
13 | floor, ceiling, truncate, round Todas estas funciones toman dos argumentos como un número y devuelven el cociente; floor devuelve el entero más grande que no es mayor que la relación, ceiling elige el número entero más pequeño que es mayor que la relación, truncate elige el número entero del mismo signo que la razón con el valor absoluto más grande que es menor que el valor absoluto de la razón, y round elige un número entero más cercano a la relación. |
14 | ffloor, fceiling, ftruncate, fround Hace lo mismo que el anterior, pero devuelve el cociente como un número de punto flotante. |
15 | mod, rem Devuelve el resto en una operación de división. |
dieciséis | float Convierte un número real en un número de coma flotante. |
17 | rational, rationalize Convierte un número real en un número racional. |
18 | numerator, denominator Devuelve las partes respectivas de un número racional. |
19 | realpart, imagpart Devuelve la parte real e imaginaria de un número complejo. |
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (/ 45 78))
(terpri)
(write (floor 45 78))
(terpri)
(write (/ 3456 75))
(terpri)
(write (floor 3456 75))
(terpri)
(write (ceiling 3456 75))
(terpri)
(write (truncate 3456 75))
(terpri)
(write (round 3456 75))
(terpri)
(write (ffloor 3456 75))
(terpri)
(write (fceiling 3456 75))
(terpri)
(write (ftruncate 3456 75))
(terpri)
(write (fround 3456 75))
(terpri)
(write (mod 3456 75))
(terpri)
(setq c (complex 6 7))
(write c)
(terpri)
(write (complex 5 -9))
(terpri)
(write (realpart c))
(terpri)
(write (imagpart c))
Cuando ejecuta el código, devuelve el siguiente resultado:
15/26
0
1152/25
46
47
46
46
46.0
47.0
46.0
46.0
6
#C(6 7)
#C(5 -9)
6
7
En LISP, los caracteres se representan como objetos de datos de tipo character.
Puede indicar un objeto de carácter que precede a # \ antes del propio carácter. Por ejemplo, # \ a significa el carácter a.
El espacio y otros caracteres especiales se pueden indicar precediendo # \ antes del nombre del carácter. Por ejemplo, # \ SPACE representa el carácter de espacio.
El siguiente ejemplo demuestra esto:
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write 'a)
(terpri)
(write #\a)
(terpri)
(write-char #\a)
(terpri)
(write-char 'a)
Cuando ejecuta el código, devuelve el siguiente resultado:
A
#\a
a
*** - WRITE-CHAR: argument A is not a character
Caracteres especiales
Common LISP permite usar los siguientes caracteres especiales en su código. Se les llama caracteres semi-estándar.
- #\Backspace
- #\Tab
- #\Linefeed
- #\Page
- #\Return
- #\Rubout
Funciones de comparación de caracteres
Las funciones y operadores de comparación numérica, como <y> no funcionan con caracteres. Common LISP proporciona otros dos conjuntos de funciones para comparar caracteres en su código.
Un conjunto distingue entre mayúsculas y minúsculas y el otro no distingue entre mayúsculas y minúsculas.
La siguiente tabla proporciona las funciones:
Funciones sensibles a mayúsculas y minúsculas | Funciones que no distinguen entre mayúsculas y minúsculas | Descripción |
---|---|---|
char = | igual a carboncillo | Comprueba si los valores de los operandos son todos iguales o no, si es así, la condición se convierte en verdadera. |
char / = | char-no-igual | Comprueba si los valores de los operandos son todos diferentes o no, si los valores no son iguales, la condición se convierte en verdadera. |
char < | char-lessp | Comprueba si los valores de los operandos disminuyen monótonamente. |
char> | char-mayorp | Comprueba si los valores de los operandos aumentan monótonamente. |
char <= | char-not-mayorp | Comprueba si el valor de cualquier operando izquierdo es mayor o igual que el valor del siguiente operando derecho, si es así, la condición se convierte en verdadera. |
char> = | char-not-lessp | Comprueba si el valor de cualquier operando de la izquierda es menor o igual que el valor de su operando de la derecha, si es así, la condición se convierte en verdadera. |
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
; case-sensitive comparison
(write (char= #\a #\b))
(terpri)
(write (char= #\a #\a))
(terpri)
(write (char= #\a #\A))
(terpri)
;case-insensitive comparision
(write (char-equal #\a #\A))
(terpri)
(write (char-equal #\a #\b))
(terpri)
(write (char-lessp #\a #\b #\c))
(terpri)
(write (char-greaterp #\a #\b #\c))
Cuando ejecuta el código, devuelve el siguiente resultado:
NIL
T
NIL
T
NIL
T
NIL
LISP le permite definir matrices de una o varias dimensiones utilizando el make-arrayfunción. Una matriz puede almacenar cualquier objeto LISP como sus elementos.
Todas las matrices constan de ubicaciones de memoria contiguas. La dirección más baja corresponde al primer elemento y la dirección más alta al último elemento.
El número de dimensiones de una matriz se denomina rango.
En LISP, un elemento de matriz se especifica mediante una secuencia de índices enteros no negativos. La longitud de la secuencia debe ser igual al rango de la matriz. La indexación comienza desde cero.
Por ejemplo, para crear una matriz con 10 celdas, llamada my-array, podemos escribir:
(setf my-array (make-array '(10)))
La función aref permite acceder al contenido de las celdas. Toma dos argumentos, el nombre de la matriz y el valor del índice.
Por ejemplo, para acceder al contenido de la décima celda, escribimos:
(aref my-array 9)
Ejemplo 1
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (setf my-array (make-array '(10))))
(terpri)
(setf (aref my-array 0) 25)
(setf (aref my-array 1) 23)
(setf (aref my-array 2) 45)
(setf (aref my-array 3) 10)
(setf (aref my-array 4) 20)
(setf (aref my-array 5) 17)
(setf (aref my-array 6) 25)
(setf (aref my-array 7) 19)
(setf (aref my-array 8) 67)
(setf (aref my-array 9) 30)
(write my-array)
Cuando ejecuta el código, devuelve el siguiente resultado:
#(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)
#(25 23 45 10 20 17 25 19 67 30)
Ejemplo 2
Creemos una matriz de 3 por 3.
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setf x (make-array '(3 3)
:initial-contents '((0 1 2 ) (3 4 5) (6 7 8)))
)
(write x)
Cuando ejecuta el código, devuelve el siguiente resultado:
#2A((0 1 2) (3 4 5) (6 7 8))
Ejemplo 3
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq a (make-array '(4 3)))
(dotimes (i 4)
(dotimes (j 3)
(setf (aref a i j) (list i 'x j '= (* i j)))
)
)
(dotimes (i 4)
(dotimes (j 3)
(print (aref a i j))
)
)
Cuando ejecuta el código, devuelve el siguiente resultado:
(0 X 0 = 0)
(0 X 1 = 0)
(0 X 2 = 0)
(1 X 0 = 0)
(1 X 1 = 1)
(1 X 2 = 2)
(2 X 0 = 0)
(2 X 1 = 2)
(2 X 2 = 4)
(3 X 0 = 0)
(3 X 1 = 3)
(3 X 2 = 6)
Sintaxis completa para la función make-array
La función make-array toma muchos otros argumentos. Veamos la sintaxis completa de esta función:
make-array dimensions :element-type :initial-element :initial-contents :adjustable :fill-pointer :displaced-to :displaced-index-offset
Aparte del argumento de las dimensiones , todos los demás argumentos son palabras clave. La siguiente tabla proporciona una breve descripción de los argumentos.
No Señor. | Argumento y descripción |
---|---|
1 | dimensions Da las dimensiones de la matriz. Es un número para una matriz unidimensional y una lista para una matriz multidimensional. |
2 | :element-type Es el especificador de tipo, el valor predeterminado es T, es decir, cualquier tipo |
3 | :initial-element Valor de los elementos iniciales. Hará una matriz con todos los elementos inicializados a un valor particular. |
4 | :initial-content Contenido inicial como objeto. |
5 | :adjustable Ayuda a crear un vector redimensionable (o ajustable) cuya memoria subyacente puede redimensionarse. El argumento es un valor booleano que indica si la matriz es ajustable o no, siendo el valor predeterminado NIL. |
6 | :fill-pointer Realiza un seguimiento del número de elementos realmente almacenados en un vector redimensionable. |
7 | :displaced-to Ayuda a crear una matriz desplazada o una matriz compartida que comparte su contenido con la matriz especificada. Ambas matrices deben tener el mismo tipo de elemento. La opción: desplazado-a no se puede utilizar con la opción: elemento-inicial o: contenido-inicial. Este argumento por defecto es nulo. |
8 | :displaced-index-offset Da el índice de desplazamiento de la matriz compartida creada. |
Ejemplo 4
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq myarray (make-array '(3 2 3)
:initial-contents
'(((a b c) (1 2 3))
((d e f) (4 5 6))
((g h i) (7 8 9))
))
)
(setq array2 (make-array 4 :displaced-to myarray :displaced-index-offset 2))
(write myarray)
(terpri)
(write array2)
Cuando ejecuta el código, devuelve el siguiente resultado:
#3A(((A B C) (1 2 3)) ((D E F) (4 5 6)) ((G H I) (7 8 9)))
#(C 1 2 3)
Si la matriz desplazada es bidimensional -
(setq myarray (make-array '(3 2 3)
:initial-contents
'(((a b c) (1 2 3))
((d e f) (4 5 6))
((g h i) (7 8 9))
))
)
(setq array2 (make-array '(3 2) :displaced-to myarray :displaced-index-offset 2))
(write myarray)
(terpri)
(write array2)
Cuando ejecuta el código, devuelve el siguiente resultado:
#3A(((A B C) (1 2 3)) ((D E F) (4 5 6)) ((G H I) (7 8 9)))
#2A((C 1) (2 3) (D E))
Cambiemos el desplazamiento del índice desplazado a 5 -
(setq myarray (make-array '(3 2 3)
:initial-contents
'(((a b c) (1 2 3))
((d e f) (4 5 6))
((g h i) (7 8 9))
))
)
(setq array2 (make-array '(3 2) :displaced-to myarray :displaced-index-offset 5))
(write myarray)
(terpri)
(write array2)
Cuando ejecuta el código, devuelve el siguiente resultado:
#3A(((A B C) (1 2 3)) ((D E F) (4 5 6)) ((G H I) (7 8 9)))
#2A((3 D) (E F) (4 5))
Ejemplo 5
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
;a one dimensional array with 5 elements,
;initail value 5
(write (make-array 5 :initial-element 5))
(terpri)
;two dimensional array, with initial element a
(write (make-array '(2 3) :initial-element 'a))
(terpri)
;an array of capacity 14, but fill pointer 5, is 5
(write(length (make-array 14 :fill-pointer 5)))
(terpri)
;however its length is 14
(write (array-dimensions (make-array 14 :fill-pointer 5)))
(terpri)
; a bit array with all initial elements set to 1
(write(make-array 10 :element-type 'bit :initial-element 1))
(terpri)
; a character array with all initial elements set to a
; is a string actually
(write(make-array 10 :element-type 'character :initial-element #\a))
(terpri)
; a two dimensional array with initial values a
(setq myarray (make-array '(2 2) :initial-element 'a :adjustable t))
(write myarray)
(terpri)
;readjusting the array
(adjust-array myarray '(1 3) :initial-element 'b)
(write myarray)
Cuando ejecuta el código, devuelve el siguiente resultado:
#(5 5 5 5 5)
#2A((A A A) (A A A))
5
(14)
#*1111111111
"aaaaaaaaaa"
#2A((A A) (A A))
#2A((A A B))
Las cadenas en Common Lisp son vectores, es decir, una matriz unidimensional de caracteres.
Los literales de cadena se encierran entre comillas dobles. Cualquier carácter admitido por el conjunto de caracteres se puede encerrar entre comillas dobles para formar una cadena, excepto el carácter de comillas dobles (") y el carácter de escape (\). Sin embargo, puede incluirlos escapándolos con una barra invertida (\).
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write-line "Hello World")
(write-line "Welcome to Tutorials Point")
;escaping the double quote character
(write-line "Welcome to \"Tutorials Point\"")
Cuando ejecuta el código, devuelve el siguiente resultado:
Hello World
Welcome to Tutorials Point
Welcome to "Tutorials Point"
Funciones de comparación de cadenas
Las funciones y operadores de comparación numérica, como <y> no funcionan en cadenas. Common LISP proporciona otros dos conjuntos de funciones para comparar cadenas en su código. Un conjunto distingue entre mayúsculas y minúsculas y el otro no distingue entre mayúsculas y minúsculas.
La siguiente tabla proporciona las funciones:
Funciones sensibles a mayúsculas y minúsculas | Funciones que no distinguen entre mayúsculas y minúsculas | Descripción |
---|---|---|
cadena = | igual a cadena | Comprueba si los valores de los operandos son todos iguales o no, si es así, la condición se convierte en verdadera. |
cadena / = | cadena-no-igual | Comprueba si los valores de los operandos son todos diferentes o no, si los valores no son iguales, la condición se convierte en verdadera. |
cadena < | string-lessp | Comprueba si los valores de los operandos disminuyen monótonamente. |
cadena> | cadena-mayor | Comprueba si los valores de los operandos aumentan monótonamente. |
cadena <= | cadena-no-mayorp | Comprueba si el valor de cualquier operando izquierdo es mayor o igual que el valor del siguiente operando derecho, si es así, la condición se convierte en verdadera. |
cadena> = | cadena-no-menosp | Comprueba si el valor de cualquier operando de la izquierda es menor o igual que el valor de su operando de la derecha, si es así, la condición se convierte en verdadera. |
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
; case-sensitive comparison
(write (string= "this is test" "This is test"))
(terpri)
(write (string> "this is test" "This is test"))
(terpri)
(write (string< "this is test" "This is test"))
(terpri)
;case-insensitive comparision
(write (string-equal "this is test" "This is test"))
(terpri)
(write (string-greaterp "this is test" "This is test"))
(terpri)
(write (string-lessp "this is test" "This is test"))
(terpri)
;checking non-equal
(write (string/= "this is test" "this is Test"))
(terpri)
(write (string-not-equal "this is test" "This is test"))
(terpri)
(write (string/= "lisp" "lisping"))
(terpri)
(write (string/= "decent" "decency"))
Cuando ejecuta el código, devuelve el siguiente resultado:
NIL
0
NIL
T
NIL
NIL
8
NIL
4
5
Funciones de control de casos
La siguiente tabla describe las funciones de control de casos:
No Señor. | Función descriptiva |
---|---|
1 | string-upcase Convierte la cadena a mayúsculas |
2 | string-downcase Convierte la cadena a minúsculas |
3 | string-capitalize Capitaliza cada palabra en la cadena |
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write-line (string-upcase "a big hello from tutorials point"))
(write-line (string-capitalize "a big hello from tutorials point"))
Cuando ejecuta el código, devuelve el siguiente resultado:
A BIG HELLO FROM TUTORIALS POINT
A Big Hello From Tutorials Point
Recortar cuerdas
La siguiente tabla describe las funciones de recorte de cuerdas:
No Señor. | Función descriptiva |
---|---|
1 | string-trim Toma una cadena de caracteres como primer argumento y una cadena como segundo argumento y devuelve una subcadena donde todos los caracteres que están en el primer argumento se eliminan de la cadena de argumentos. |
2 | String-left-trim Toma una cadena de caracteres como primer argumento y una cadena como segundo argumento y devuelve una subcadena donde todos los caracteres que están en el primer argumento se eliminan del principio de la cadena del argumento. |
3 | String-right-trim Toma un carácter de cadena como primer argumento y una cadena como segundo argumento y devuelve una subcadena donde todos los caracteres que están en el primer argumento se eliminan del final de la cadena de argumentos. |
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write-line (string-trim " " " a big hello from tutorials point "))
(write-line (string-left-trim " " " a big hello from tutorials point "))
(write-line (string-right-trim " " " a big hello from tutorials point "))
(write-line (string-trim " a" " a big hello from tutorials point "))
Cuando ejecuta el código, devuelve el siguiente resultado:
a big hello from tutorials point
a big hello from tutorials point
a big hello from tutorials point
big hello from tutorials point
Otras funciones de cadena
Las cadenas de LISP son matrices y, por tanto, también secuencias. Cubriremos estos tipos de datos en los próximos tutoriales. Todas las funciones que son aplicables a matrices y secuencias también se aplican a cadenas. Sin embargo, demostraremos algunas funciones de uso común usando varios ejemplos.
Calcular la longitud
los length La función calcula la longitud de una cadena.
Extrayendo subcadena
los subseq La función devuelve una subcadena (ya que una cadena también es una secuencia) que comienza en un índice particular y continúa hasta un índice final particular o el final de la cadena.
Acceder a un personaje en una cadena
los char La función permite acceder a caracteres individuales de una cadena.
Example
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (length "Hello World"))
(terpri)
(write-line (subseq "Hello World" 6))
(write (char "Hello World" 6))
Cuando ejecuta el código, devuelve el siguiente resultado:
11
World
#\W
Clasificación y fusión de cadenas
los sortLa función permite ordenar una cadena. Toma una secuencia (vector o cadena) y un predicado de dos argumentos y devuelve una versión ordenada de la secuencia.
los merge La función toma dos secuencias y un predicado y devuelve una secuencia producida al fusionar las dos secuencias, de acuerdo con el predicado.
Example
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
;sorting the strings
(write (sort (vector "Amal" "Akbar" "Anthony") #'string<))
(terpri)
;merging the strings
(write (merge 'vector (vector "Rishi" "Zara" "Priyanka")
(vector "Anju" "Anuj" "Avni") #'string<))
Cuando ejecuta el código, devuelve el siguiente resultado:
#("Akbar" "Amal" "Anthony")
#("Anju" "Anuj" "Avni" "Rishi" "Zara" "Priyanka")
Inversión de una cuerda
los reverse función invierte una cadena.
Por ejemplo, cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write-line (reverse "Are we not drawn onward, we few, drawn onward to new era"))
Cuando ejecuta el código, devuelve el siguiente resultado:
are wen ot drawno nward ,wef ew ,drawno nward ton ew erA
Concatenación de cadenas
La función concatenar concatena dos cadenas. Esta es una función de secuencia genérica y debe proporcionar el tipo de resultado como primer argumento.
Por ejemplo, cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write-line (concatenate 'string "Are we not drawn onward, " "we few, drawn onward to new era"))
Cuando ejecuta el código, devuelve el siguiente resultado:
Are we not drawn onward, we few, drawn onward to new era
La secuencia es un tipo de datos abstracto en LISP. Los vectores y las listas son los dos subtipos concretos de este tipo de datos. Todas las funcionalidades definidas en el tipo de datos de secuencia se aplican realmente en todos los tipos de vectores y listas.
En esta sección, discutiremos las funciones más comúnmente utilizadas en secuencias.
Antes de comenzar con varias formas de manipular secuencias (es decir, vectores y listas), echemos un vistazo a la lista de todas las funciones disponibles.
Crear una secuencia
La función make-sequence le permite crear una secuencia de cualquier tipo. La sintaxis de esta función es:
make-sequence sqtype sqsize &key :initial-element
Crea una secuencia de tipo sqtype y de longitud sqsize.
Opcionalmente, puede especificar algún valor usando el argumento : initial-element , luego cada uno de los elementos se inicializará con este valor.
Por ejemplo, cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (make-sequence '(vector float)
10
:initial-element 1.0))
Cuando ejecuta el código, devuelve el siguiente resultado:
#(1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0)
Funciones genéricas en secuencias
No Señor. | Función descriptiva |
---|---|
1 | elt Permite el acceso a elementos individuales a través de un índice entero. |
2 | length Devuelve la longitud de una secuencia. |
3 | subseq Devuelve una subsecuencia extrayendo la subsecuencia comenzando en un índice particular y continuando hasta un índice final particular o el final de la secuencia. |
4 | copy-seq Devuelve una secuencia que contiene los mismos elementos que su argumento. |
5 | fill Se utiliza para establecer varios elementos de una secuencia en un solo valor. |
6 | replace Toma dos secuencias y la primera secuencia de argumentos se modifica de forma destructiva copiando en ella elementos sucesivos de la segunda secuencia de argumentos. |
7 | count Toma un elemento y una secuencia y devuelve el número de veces que el elemento aparece en la secuencia. |
8 | reverse Devuelve una secuencia que contiene los mismos elementos del argumento pero en orden inverso. |
9 | nreverse Devuelve la misma secuencia que contiene los mismos elementos que la secuencia pero en orden inverso. |
10 | concatenate Crea una nueva secuencia que contiene la concatenación de cualquier número de secuencias. |
11 | position Toma un elemento y una secuencia y devuelve el índice del elemento en la secuencia o nulo. |
12 | find Se necesita un elemento y una secuencia. Encuentra el elemento en la secuencia y lo devuelve, si no lo encuentra, devuelve nil. |
13 | sort Toma una secuencia y un predicado de dos argumentos y devuelve una versión ordenada de la secuencia. |
14 | merge Toma dos secuencias y un predicado y devuelve una secuencia producida al fusionar las dos secuencias, de acuerdo con el predicado. |
15 | map Toma una función de n argumentos yn secuencias y devuelve una nueva secuencia que contiene el resultado de aplicar la función a los elementos subsiguientes de las secuencias. |
dieciséis | some Toma un predicado como argumento e itera sobre la secuencia de argumentos, y devuelve el primer valor no NIL devuelto por el predicado o devuelve falso si el predicado nunca se satisface. |
17 | every Toma un predicado como argumento e itera sobre la secuencia del argumento, termina y devuelve falso tan pronto como falla el predicado. Si el predicado siempre se satisface, devuelve verdadero. |
18 | notany Toma un predicado como argumento e itera sobre la secuencia del argumento, y devuelve falso tan pronto como se satisfaga el predicado o verdadero si nunca lo es. |
19 | notevery Toma un predicado como argumento e itera sobre la secuencia del argumento, y devuelve verdadero tan pronto como el predicado falla o falso si el predicado siempre se satisface. |
20 | reduce Se mapea sobre una sola secuencia, aplicando una función de dos argumentos primero a los dos primeros elementos de la secuencia y luego al valor devuelto por la función y los elementos subsiguientes de la secuencia. |
21 | search Busca una secuencia para localizar uno o más elementos que satisfacen alguna prueba. |
22 | remove Toma un elemento y una secuencia y devuelve la secuencia con instancias de elemento eliminado. |
23 | delete Esto también toma un elemento y una secuencia y devuelve una secuencia del mismo tipo que la secuencia de argumentos que tiene los mismos elementos excepto el elemento. |
24 | substitute Toma un artículo nuevo, un artículo existente y una secuencia y devuelve una secuencia con instancias del artículo existente reemplazado por el nuevo artículo. |
25 | nsubstitute Toma un nuevo artículo, un artículo existente y una secuencia y devuelve la misma secuencia con instancias del artículo existente reemplazado por el nuevo artículo. |
26 | mismatch Toma dos secuencias y devuelve el índice del primer par de elementos no coincidentes. |
Argumentos de palabras clave de función de secuencia estándar
Argumento | Sentido | Valor por defecto |
---|---|---|
:prueba | Es una función de dos argumentos que se utiliza para comparar el elemento (o el valor extraído por: función clave) con el elemento. | EQL |
:llave | Función de un argumento para extraer el valor clave del elemento de secuencia real. NIL significa usar el elemento tal cual. | NULO |
:comienzo | Índice de inicio (incluido) de la subsecuencia. | 0 |
:fin | Índice final (exclusivo) de la subsecuencia. NIL indica el final de la secuencia. | NULO |
: desde el final | Si es verdadero, la secuencia se recorrerá en orden inverso, de principio a fin. | NULO |
:contar | Número que indica el número de elementos a eliminar o sustituir o NULO para indicar todos (sólo ELIMINAR y SUSTITUIR). | NULO |
Acabamos de discutir varias funciones y palabras clave que se utilizan como argumentos en estas funciones que trabajan en secuencias. En las siguientes secciones, veremos cómo usar estas funciones usando ejemplos.
Encontrar longitud y elemento
los length La función devuelve la longitud de una secuencia y la elt La función le permite acceder a elementos individuales usando un índice entero.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq x (vector 'a 'b 'c 'd 'e))
(write (length x))
(terpri)
(write (elt x 3))
Cuando ejecuta el código, devuelve el siguiente resultado:
5
D
Modificar secuencias
Algunas funciones de secuencia permiten iterar a través de la secuencia y realizar algunas operaciones como buscar, eliminar, contar o filtrar elementos específicos sin escribir bucles explícitos.
El siguiente ejemplo demuestra esto:
Ejemplo 1
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (count 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (remove 5 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (delete 5 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (substitute 10 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (find 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (position 5 '(1 5 6 7 8 9 2 7 3 4 5)))
Cuando ejecuta el código, devuelve el siguiente resultado:
2
(1 6 7 8 9 2 7 3 4)
(1 6 7 8 9 2 7 3 4)
(1 5 6 10 8 9 2 10 3 4 5)
7
1
Ejemplo 2
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (delete-if #'oddp '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (delete-if #'evenp '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (remove-if #'evenp '(1 5 6 7 8 9 2 7 3 4 5) :count 1 :from-end t))
(terpri)
(setq x (vector 'a 'b 'c 'd 'e 'f 'g))
(fill x 'p :start 1 :end 4)
(write x)
Cuando ejecuta el código, devuelve el siguiente resultado:
(6 8 2 4)
(1 5 7 9 7 3 5)
(1 5 6 7 8 9 2 7 3 5)
#(A P P P E F G)
Ordenar y fusionar secuencias
Las funciones de clasificación toman una secuencia y un predicado de dos argumentos y devuelven una versión ordenada de la secuencia.
Ejemplo 1
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (sort '(2 4 7 3 9 1 5 4 6 3 8) #'<))
(terpri)
(write (sort '(2 4 7 3 9 1 5 4 6 3 8) #'>))
(terpri)
Cuando ejecuta el código, devuelve el siguiente resultado:
(1 2 3 3 4 4 5 6 7 8 9)
(9 8 7 6 5 4 4 3 3 2 1)
Ejemplo 2
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (merge 'vector #(1 3 5) #(2 4 6) #'<))
(terpri)
(write (merge 'list #(1 3 5) #(2 4 6) #'<))
(terpri)
Cuando ejecuta el código, devuelve el siguiente resultado:
#(1 2 3 4 5 6)
(1 2 3 4 5 6)
Predicados de secuencia
Las funciones every, some, notany y notevery se denominan predicados de secuencia.
Estas funciones iteran sobre secuencias y prueban el predicado booleano.
Todas estas funciones toman un predicado como primer argumento y los argumentos restantes son secuencias.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (every #'evenp #(2 4 6 8 10)))
(terpri)
(write (some #'evenp #(2 4 6 8 10 13 14)))
(terpri)
(write (every #'evenp #(2 4 6 8 10 13 14)))
(terpri)
(write (notany #'evenp #(2 4 6 8 10)))
(terpri)
(write (notevery #'evenp #(2 4 6 8 10 13 14)))
(terpri)
Cuando ejecuta el código, devuelve el siguiente resultado:
T
T
NIL
NIL
T
Secuencias de mapeo
Ya hemos discutido las funciones de mapeo. Similarmente elmap función le permite aplicar una función a elementos subsiguientes de una o más secuencias.
los map función toma una función de n argumentos yn secuencias y devuelve una nueva secuencia después de aplicar la función a los elementos subsiguientes de las secuencias.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (map 'vector #'* #(2 3 4 5) #(3 5 4 8)))
Cuando ejecuta el código, devuelve el siguiente resultado:
#(6 15 16 40)
Las listas habían sido la estructura de datos compuesta más importante y primaria en LISP tradicional. El Common LISP actual proporciona otras estructuras de datos como vector, tabla hash, clases o estructuras.
Las listas son listas de enlaces individuales. En LISP, las listas se construyen como una cadena de una estructura de registro simple denominadacons Unidos entre sí.
La estructura de registro de los contras
UN cons es una estructura de registro que contiene dos componentes llamados car y el cdr.
Las contras o contras son objetos que son pares de valores que se crean usando la función cons.
los consLa función toma dos argumentos y devuelve una nueva celda de cons que contiene los dos valores. Estos valores pueden ser referencias a cualquier tipo de objeto.
Si el segundo valor no es nulo, u otra celda de contras, entonces los valores se imprimen como un par de puntos entre paréntesis.
Los dos valores en una celda de contras se denominan car y el cdr. los car La función se utiliza para acceder al primer valor y al cdr La función se utiliza para acceder al segundo valor.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (cons 1 2))
(terpri)
(write (cons 'a 'b))
(terpri)
(write (cons 1 nil))
(terpri)
(write (cons 1 (cons 2 nil)))
(terpri)
(write (cons 1 (cons 2 (cons 3 nil))))
(terpri)
(write (cons 'a (cons 'b (cons 'c nil))))
(terpri)
(write ( car (cons 'a (cons 'b (cons 'c nil)))))
(terpri)
(write ( cdr (cons 'a (cons 'b (cons 'c nil)))))
Cuando ejecuta el código, devuelve el siguiente resultado:
(1 . 2)
(A . B)
(1)
(1 2)
(1 2 3)
(A B C)
A
(B C)
El ejemplo anterior muestra cómo se podrían usar las estructuras de contras para crear una única lista enlazada, por ejemplo, la lista (ABC) consta de tres celdas de contras unidas entre sí por sus cdrs .
En forma de diagrama, se podría expresar como:
Listas en LISP
Aunque las celdas contras se pueden usar para crear listas, sin embargo, construir una lista a partir de conslas llamadas a funciones no pueden ser la mejor solución. loslist La función se usa más bien para crear listas en LISP.
La función de lista puede tomar cualquier número de argumentos y, como es una función, evalúa sus argumentos.
los first y restlas funciones dan el primer elemento y el resto parte de una lista. Los siguientes ejemplos demuestran los conceptos.
Ejemplo 1
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (list 1 2))
(terpri)
(write (list 'a 'b))
(terpri)
(write (list 1 nil))
(terpri)
(write (list 1 2 3))
(terpri)
(write (list 'a 'b 'c))
(terpri)
(write (list 3 4 'a (car '(b . c)) (* 4 -2)))
(terpri)
(write (list (list 'a 'b) (list 'c 'd 'e)))
Cuando ejecuta el código, devuelve el siguiente resultado:
(1 2)
(A B)
(1 NIL)
(1 2 3)
(A B C)
(3 4 A B -8)
((A B) (C D E))
Ejemplo 2
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(defun my-library (title author rating availability)
(list :title title :author author :rating rating :availabilty availability)
)
(write (getf (my-library "Hunger Game" "Collins" 9 t) :title))
Cuando ejecuta el código, devuelve el siguiente resultado:
"Hunger Game"
Funciones de manipulación de listas
La siguiente tabla proporciona algunas funciones de manipulación de listas de uso común.
No Señor. | Función descriptiva |
---|---|
1 | car Toma una lista como argumento y devuelve su primer elemento. |
2 | cdr Toma una lista como argumento y devuelve una lista sin el primer elemento |
3 | cons Toma dos argumentos, un elemento y una lista y devuelve una lista con el elemento insertado en primer lugar. |
4 | list Toma cualquier número de argumentos y devuelve una lista con los argumentos como elementos miembros de la lista. |
5 | append Fusiona dos o más listas en una. |
6 | last Toma una lista y devuelve una lista que contiene el último elemento. |
7 | member Toma dos argumentos de los cuales el segundo debe ser una lista, si el primer argumento es miembro del segundo argumento, y luego devuelve el resto de la lista comenzando con el primer argumento. |
8 | reverse Toma una lista y devuelve una lista con los elementos superiores en orden inverso. |
Tenga en cuenta que todas las funciones de secuencia son aplicables a las listas.
Ejemplo 3
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (car '(a b c d e f)))
(terpri)
(write (cdr '(a b c d e f)))
(terpri)
(write (cons 'a '(b c)))
(terpri)
(write (list 'a '(b c) '(e f)))
(terpri)
(write (append '(b c) '(e f) '(p q) '() '(g)))
(terpri)
(write (last '(a b c d (e f))))
(terpri)
(write (reverse '(a b c d (e f))))
Cuando ejecuta el código, devuelve el siguiente resultado:
A
(B C D E F)
(A B C)
(A (B C) (E F))
(B C E F P Q G)
((E F))
((E F) D C B A)
Concatenación de funciones de coche y cdr
los car y cdr funciones y su combinación permite extraer cualquier elemento / miembro particular de una lista.
Sin embargo, las secuencias de funciones car y cdr se pueden abreviar concatenando la letra a para car yd para cdr dentro de las letras cy r.
Por ejemplo, podemos escribir cadadr para abreviar la secuencia de llamadas a funciones: car cdr car cdr.
Por lo tanto, (cadadr '(a (cd) (efg))) devolverá d
Ejemplo 4
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (cadadr '(a (c d) (e f g))))
(terpri)
(write (caar (list (list 'a 'b) 'c)))
(terpri)
(write (cadr (list (list 1 2) (list 3 4))))
(terpri)
Cuando ejecuta el código, devuelve el siguiente resultado:
D
A
(3 4)
En LISP, un símbolo es un nombre que representa objetos de datos y, curiosamente, también es un objeto de datos.
Lo que hace que los símbolos sean especiales es que tienen un componente llamado property listo plist.
Listas de propiedades
LISP le permite asignar propiedades a los símbolos. Por ejemplo, tengamos un objeto "persona". Nos gustaría que este objeto 'persona' tuviera propiedades como nombre, sexo, altura, peso, dirección, profesión, etc. Una propiedad es como un nombre de atributo.
Una lista de propiedades se implementa como una lista con un número par (posiblemente cero) de elementos. Cada par de elementos de la lista constituye una entrada; el primer elemento es elindicator, y el segundo es el value.
Cuando se crea un símbolo, su lista de propiedades está inicialmente vacía. Las propiedades se crean usandoget Dentro de un setf formar.
Por ejemplo, las siguientes declaraciones nos permiten asignar títulos de propiedades, autor y editor, y valores respectivos, a un objeto llamado (símbolo) 'libro'.
Ejemplo 1
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (setf (get 'books'title) '(Gone with the Wind)))
(terpri)
(write (setf (get 'books 'author) '(Margaret Michel)))
(terpri)
(write (setf (get 'books 'publisher) '(Warner Books)))
Cuando ejecuta el código, devuelve el siguiente resultado:
(GONE WITH THE WIND)
(MARGARET MICHEL)
(WARNER BOOKS)
Varias funciones de lista de propiedades le permiten asignar propiedades, así como recuperar, reemplazar o eliminar las propiedades de un símbolo.
los getLa función devuelve la lista de propiedades del símbolo para un indicador dado. Tiene la siguiente sintaxis:
get symbol indicator &optional default
los getla función busca la lista de propiedades del símbolo dado para el indicador especificado, si lo encuentra, devuelve el valor correspondiente; de lo contrario, se devuelve el valor predeterminado (o nulo, si no se especifica un valor predeterminado).
Ejemplo 2
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setf (get 'books 'title) '(Gone with the Wind))
(setf (get 'books 'author) '(Margaret Micheal))
(setf (get 'books 'publisher) '(Warner Books))
(write (get 'books 'title))
(terpri)
(write (get 'books 'author))
(terpri)
(write (get 'books 'publisher))
Cuando ejecuta el código, devuelve el siguiente resultado:
(GONE WITH THE WIND)
(MARGARET MICHEAL)
(WARNER BOOKS)
los symbol-plist La función le permite ver todas las propiedades de un símbolo.
Ejemplo 3
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setf (get 'annie 'age) 43)
(setf (get 'annie 'job) 'accountant)
(setf (get 'annie 'sex) 'female)
(setf (get 'annie 'children) 3)
(terpri)
(write (symbol-plist 'annie))
Cuando ejecuta el código, devuelve el siguiente resultado:
(CHILDREN 3 SEX FEMALE JOB ACCOUNTANT AGE 43)
los remprop función quita la propiedad especificada de un símbolo.
Ejemplo 4
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setf (get 'annie 'age) 43)
(setf (get 'annie 'job) 'accountant)
(setf (get 'annie 'sex) 'female)
(setf (get 'annie 'children) 3)
(terpri)
(write (symbol-plist 'annie))
(remprop 'annie 'age)
(terpri)
(write (symbol-plist 'annie))
Cuando ejecuta el código, devuelve el siguiente resultado:
(CHILDREN 3 SEX FEMALE JOB ACCOUNTANT AGE 43)
(CHILDREN 3 SEX FEMALE JOB ACCOUNTANT)
Los vectores son matrices unidimensionales, por lo tanto, un subtipo de matriz. Los vectores y las listas se denominan colectivamente secuencias. Por lo tanto, todas las funciones genéricas de secuencia y las funciones de matriz que hemos discutido hasta ahora, funcionan en vectores.
Crear vectores
La función de vector le permite crear vectores de tamaño fijo con valores específicos. Toma cualquier número de argumentos y devuelve un vector que contiene esos argumentos.
Ejemplo 1
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setf v1 (vector 1 2 3 4 5))
(setf v2 #(a b c d e))
(setf v3 (vector 'p 'q 'r 's 't))
(write v1)
(terpri)
(write v2)
(terpri)
(write v3)
Cuando ejecuta el código, devuelve el siguiente resultado:
#(1 2 3 4 5)
#(A B C D E)
#(P Q R S T)
Tenga en cuenta que LISP utiliza la sintaxis # (...) como notación literal para los vectores. Puede usar esta sintaxis # (...) para crear e incluir vectores literales en su código.
Sin embargo, estos son vectores literales, por lo que modificarlos no está definido en LISP. Por lo tanto, para programar, siempre debe usar elvector función, o la función más general make-array para crear los vectores que planea modificar.
los make-arrayLa función es la forma más genérica de crear un vector. Puede acceder a los elementos vectoriales utilizando elaref función.
Ejemplo 2
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq a (make-array 5 :initial-element 0))
(setq b (make-array 5 :initial-element 2))
(dotimes (i 5)
(setf (aref a i) i))
(write a)
(terpri)
(write b)
(terpri)
Cuando ejecuta el código, devuelve el siguiente resultado:
#(0 1 2 3 4)
#(2 2 2 2 2)
Puntero de relleno
los make-array La función le permite crear un vector de tamaño variable.
los fill-pointerEl argumento de la función realiza un seguimiento del número de elementos realmente almacenados en el vector. Es el índice de la siguiente posición que se debe llenar cuando agrega un elemento al vector.
los vector-pushLa función le permite agregar un elemento al final de un vector de tamaño variable. Aumenta el puntero de relleno en 1.
los vector-pop La función devuelve el elemento introducido más recientemente y reduce el puntero de relleno en 1.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq a (make-array 5 :fill-pointer 0))
(write a)
(vector-push 'a a)
(vector-push 'b a)
(vector-push 'c a)
(terpri)
(write a)
(terpri)
(vector-push 'd a)
(vector-push 'e a)
;this will not be entered as the vector limit is 5
(vector-push 'f a)
(write a)
(terpri)
(vector-pop a)
(vector-pop a)
(vector-pop a)
(write a)
Cuando ejecuta el código, devuelve el siguiente resultado:
#()
#(A B C)
#(A B C D E)
#(A B)
Siendo los vectores secuencias, todas las funciones de secuencia son aplicables para vectores. Consulte el capítulo de secuencias, para funciones vectoriales.
Common Lisp no proporciona un tipo de datos establecido. Sin embargo, proporciona una serie de funciones que permiten realizar operaciones de conjunto en una lista.
Puede agregar, eliminar y buscar elementos en una lista, según varios criterios. También puede realizar varias operaciones de conjuntos como: unión, intersección y diferencia de conjuntos.
Implementación de conjuntos en LISP
Los conjuntos, como las listas, se implementan generalmente en términos de celdas de cons. Sin embargo, por esta misma razón, las operaciones de conjuntos se vuelven cada vez menos eficientes cuanto más grandes se vuelven los conjuntos.
los adjoinLa función le permite crear un conjunto. Toma un elemento y una lista que representa un conjunto y devuelve una lista que representa el conjunto que contiene el elemento y todos los elementos del conjunto original.
los adjoinla función primero busca el elemento en la lista dada, si se encuentra, luego devuelve la lista original; de lo contrario, crea una nueva celda de contras con sucar como el artículo y cdr apunta a la lista original y devuelve esta nueva lista.
los adjoin la función también toma :key y :testargumentos de palabras clave. Estos argumentos se utilizan para comprobar si el elemento está presente en la lista original.
Dado que la función adjunta no modifica la lista original, para realizar un cambio en la lista en sí, debe asignar el valor devuelto por adjunto a la lista original o puede usar la macro pushnew para agregar un artículo al conjunto.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
; creating myset as an empty list
(defparameter *myset* ())
(adjoin 1 *myset*)
(adjoin 2 *myset*)
; adjoin did not change the original set
;so it remains same
(write *myset*)
(terpri)
(setf *myset* (adjoin 1 *myset*))
(setf *myset* (adjoin 2 *myset*))
;now the original set is changed
(write *myset*)
(terpri)
;adding an existing value
(pushnew 2 *myset*)
;no duplicate allowed
(write *myset*)
(terpri)
;pushing a new value
(pushnew 3 *myset*)
(write *myset*)
(terpri)
Cuando ejecuta el código, devuelve el siguiente resultado:
NIL
(2 1)
(2 1)
(3 2 1)
Comprobación de membresía
El grupo de funciones de miembros le permite verificar si un elemento es miembro de un conjunto o no.
Las siguientes son las sintaxis de estas funciones:
member item list &key :test :test-not :key
member-if predicate list &key :key
member-if-not predicate list &key :key
Estas funciones buscan en la lista dada un elemento dado que satisfaga la prueba. Si no se encuentra tal elemento, las funciones devuelvennil. De lo contrario, se devuelve la cola de la lista con el elemento como primer elemento.
La búsqueda se realiza solo en el nivel superior.
Estas funciones pueden usarse como predicados.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(write (member 'zara '(ayan abdul zara riyan nuha)))
(terpri)
(write (member-if #'evenp '(3 7 2 5/3 'a)))
(terpri)
(write (member-if-not #'numberp '(3 7 2 5/3 'a 'b 'c)))
Cuando ejecuta el código, devuelve el siguiente resultado:
(ZARA RIYAN NUHA)
(2 5/3 'A)
('A 'B 'C)
Establecer unión
El grupo de funciones de unión le permite realizar una unión de conjuntos en dos listas proporcionadas como argumentos para estas funciones sobre la base de una prueba.
Las siguientes son las sintaxis de estas funciones:
union list1 list2 &key :test :test-not :key
nunion list1 list2 &key :test :test-not :key
los unionLa función toma dos listas y devuelve una nueva lista que contiene todos los elementos presentes en cualquiera de las listas. Si hay duplicaciones, solo se conserva una copia del miembro en la lista devuelta.
los nunion La función realiza la misma operación pero puede destruir las listas de argumentos.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq set1 (union '(a b c) '(c d e)))
(setq set2 (union '(#(a b) #(5 6 7) #(f h))
'(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch)
)
(setq set3 (union '(#(a b) #(5 6 7) #(f h))
'(#(5 6 7) #(a b) #(g h)))
)
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)
Cuando ejecuta el código, devuelve el siguiente resultado:
(A B C D E)
(#(F H) #(5 6 7) #(A B) #(G H))
(#(A B) #(5 6 7) #(F H) #(5 6 7) #(A B) #(G H))
Tenga en cuenta
La función de unión no funciona como se esperaba sin :test-not #'mismatchargumentos para una lista de tres vectores. Esto se debe a que las listas están hechas de celdas de contras y, aunque aparentemente los valores nos parecen los mismos,cdrparte de las celdas no coincide, por lo que no son exactamente iguales al intérprete / compilador LISP. Esta es la razón; No se recomienda implementar grandes conjuntos usando listas. Sin embargo, funciona bien para juegos pequeños.
Establecer intersección
El grupo de funciones de intersección le permite realizar la intersección en dos listas proporcionadas como argumentos para estas funciones sobre la base de una prueba.
Las siguientes son las sintaxis de estas funciones:
intersection list1 list2 &key :test :test-not :key
nintersection list1 list2 &key :test :test-not :key
Estas funciones toman dos listas y devuelven una nueva lista que contiene todos los elementos presentes en ambas listas de argumentos. Si alguna de las listas tiene entradas duplicadas, las entradas redundantes pueden aparecer o no en el resultado.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq set1 (intersection '(a b c) '(c d e)))
(setq set2 (intersection '(#(a b) #(5 6 7) #(f h))
'(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch)
)
(setq set3 (intersection '(#(a b) #(5 6 7) #(f h))
'(#(5 6 7) #(a b) #(g h)))
)
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)
Cuando ejecuta el código, devuelve el siguiente resultado:
(C)
(#(A B) #(5 6 7))
NIL
La función de intersección es la versión destructiva de la intersección, es decir, puede destruir las listas originales.
Establecer diferencia
El grupo de funciones de diferencias de conjuntos le permite realizar diferencias de conjuntos en dos listas proporcionadas como argumentos para estas funciones sobre la base de una prueba.
Las siguientes son las sintaxis de estas funciones:
set-difference list1 list2 &key :test :test-not :key
nset-difference list1 list2 &key :test :test-not :key
La función de diferencia de conjuntos devuelve una lista de elementos de la primera lista que no aparecen en la segunda lista.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq set1 (set-difference '(a b c) '(c d e)))
(setq set2 (set-difference '(#(a b) #(5 6 7) #(f h))
'(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch)
)
(setq set3 (set-difference '(#(a b) #(5 6 7) #(f h))
'(#(5 6 7) #(a b) #(g h)))
)
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)
Cuando ejecuta el código, devuelve el siguiente resultado:
(A B)
(#(F H))
(#(A B) #(5 6 7) #(F H))
Puede construir estructuras de datos de árbol a partir de celdas de contras, como listas de listas.
Para implementar estructuras de árbol, tendrá que diseñar funcionalidades que atraviesen las celdas de contras, en un orden específico, por ejemplo, preorden, en orden y posorden para árboles binarios.
Árbol como lista de listas
Consideremos una estructura de árbol formada por celdas de contras que forman la siguiente lista de listas:
((1 2) (3 4) (5 6)).
En forma de diagrama, se podría expresar como:
Funciones de árbol en LISP
Aunque principalmente necesitará escribir sus propias funcionalidades de árbol de acuerdo con sus necesidades específicas, LISP proporciona algunas funciones de árbol que puede utilizar.
Aparte de todas las funciones de lista, las siguientes funciones funcionan especialmente en estructuras de árbol:
No Señor. | Función descriptiva |
---|---|
1 | copy-tree x y vecp opcional Devuelve una copia del árbol de contras celdas x. Copia recursivamente las direcciones del coche y del CDR. Si x no es una celda de cons, la función simplemente devuelve x sin cambios. Si el argumento opcional vecp es verdadero, esta función copia vectores (recursivamente) así como celdas de cons. |
2 | tree-equal xy & key: test: test-not: key Compara dos árboles de células contras. Si xey son ambas celdas de cons, sus coches y cdrs se comparan de forma recursiva. Si ni x ni y son una celda de cons, se comparan mediante eql, o de acuerdo con la prueba especificada. La función de tecla:, si se especifica, se aplica a los elementos de ambos árboles. |
3 | subst nuevo árbol antiguo y clave: prueba: prueba-no: clave Sustituye las apariciones de un elemento antiguo dado con un elemento nuevo , en el árbol , que es un árbol de celdas de contras. |
4 | nsubst nuevo árbol antiguo y clave: prueba: prueba-no: clave Funciona igual que subst, pero destruye el árbol original. |
5 | sublis árbol de lista y clave: prueba: prueba-no: clave Funciona como subst, excepto que toma una lista de asociación a-lista de los viejos-nuevos pares. Cada elemento del árbol (después de aplicar la función de tecla:, si existe), se compara con los carros de una lista; si coincide, se reemplaza por el cdr correspondiente. |
6 | nsublis árbol de lista y clave: prueba: prueba-no: clave Funciona igual que sublis, pero en una versión destructiva. |
Ejemplo 1
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq lst (list '(1 2) '(3 4) '(5 6)))
(setq mylst (copy-list lst))
(setq tr (copy-tree lst))
(write lst)
(terpri)
(write mylst)
(terpri)
(write tr)
Cuando ejecuta el código, devuelve el siguiente resultado:
((1 2) (3 4) (5 6))
((1 2) (3 4) (5 6))
((1 2) (3 4) (5 6))
Ejemplo 2
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq tr '((1 2 (3 4 5) ((7 8) (7 8 9)))))
(write tr)
(setq trs (subst 7 1 tr))
(terpri)
(write trs)
Cuando ejecuta el código, devuelve el siguiente resultado:
((1 2 (3 4 5) ((7 8) (7 8 9))))
((7 2 (3 4 5) ((7 8) (7 8 9))))
Construyendo su propio árbol
Intentemos construir nuestro propio árbol, usando las funciones de lista disponibles en LISP.
Primero, creemos un nuevo nodo que contenga algunos datos.
(defun make-tree (item)
"it creates a new node with item."
(cons (cons item nil) nil)
)
A continuación, agreguemos un nodo hijo en el árbol: tomará dos nodos de árbol y agregará el segundo árbol como hijo del primero.
(defun add-child (tree child)
(setf (car tree) (append (car tree) child))
tree)
Esta función devolverá al primer hijo de un árbol determinado; tomará un nodo de árbol y devolverá el primer hijo de ese nodo, o nulo, si este nodo no tiene ningún nodo hijo.
(defun first-child (tree)
(if (null tree)
nil
(cdr (car tree))
)
)
Esta función devolverá el siguiente hermano de un nodo dado: toma un nodo de árbol como argumento y devuelve una referencia al siguiente nodo hermano, o nil, si el nodo no tiene ninguno.
(defun next-sibling (tree)
(cdr tree)
)
Por último, necesitamos una función para devolver la información en un nodo:
(defun data (tree)
(car (car tree))
)
Ejemplo
Este ejemplo utiliza las funcionalidades anteriores:
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(defun make-tree (item)
"it creates a new node with item."
(cons (cons item nil) nil)
)
(defun first-child (tree)
(if (null tree)
nil
(cdr (car tree))
)
)
(defun next-sibling (tree)
(cdr tree)
)
(defun data (tree)
(car (car tree))
)
(defun add-child (tree child)
(setf (car tree) (append (car tree) child))
tree
)
(setq tr '((1 2 (3 4 5) ((7 8) (7 8 9)))))
(setq mytree (make-tree 10))
(write (data mytree))
(terpri)
(write (first-child tr))
(terpri)
(setq newtree (add-child tr mytree))
(terpri)
(write newtree)
Cuando ejecuta el código, devuelve el siguiente resultado:
10
(2 (3 4 5) ((7 8) (7 8 9)))
((1 2 (3 4 5) ((7 8) (7 8 9)) (10)))
La estructura de datos de la tabla hash representa una colección de key-and-valuepares que se organizan en función del código hash de la clave. Utiliza la clave para acceder a los elementos de la colección.
Se utiliza una tabla hash cuando necesita acceder a elementos mediante una clave y puede identificar un valor clave útil. Cada elemento de la tabla hash tiene un par clave / valor. La clave se utiliza para acceder a los elementos de la colección.
Crear tabla hash en LISP
En Common LISP, la tabla hash es una colección de uso general. Puede utilizar objetos arbitrarios como clave o índices.
Cuando almacena un valor en una tabla hash, crea un par clave-valor y lo almacena bajo esa clave. Más tarde, puede recuperar el valor de la tabla hash utilizando la misma clave. Cada clave se asigna a un valor único, aunque puede almacenar un nuevo valor en una clave.
Las tablas hash, en LISP, se pueden clasificar en tres tipos, según la forma en que se pueden comparar las claves: eq, eql o igual. Si la tabla hash tiene un hash en los objetos LISP, las claves se comparan con eq o eql. Si el hash de la tabla hash en la estructura de árbol, entonces se compararía usando igual.
los make-hash-tableLa función se utiliza para crear una tabla hash. La sintaxis de esta función es:
make-hash-table &key :test :size :rehash-size :rehash-threshold
Donde -
los key El argumento proporciona la clave.
los :testEl argumento determina cómo se comparan las claves: debe tener uno de los tres valores # 'eq, #' eql o # 'igual, o uno de los tres símbolos eq, eql o igual. Si no se especifica, se asume eql.
los :sizeEl argumento establece el tamaño inicial de la tabla hash. Debe ser un número entero mayor que cero.
los :rehash-sizeEl argumento especifica cuánto aumentar el tamaño de la tabla hash cuando se llena. Puede ser un número entero mayor que cero, que es el número de entradas que se agregarán, o puede ser un número de punto flotante mayor que 1, que es la relación entre el tamaño nuevo y el tamaño anterior. El valor predeterminado de este argumento depende de la implementación.
los :rehash-thresholdEl argumento especifica qué tan llena puede estar la tabla hash antes de que deba crecer. Puede ser un número entero mayor que cero y menor que: rehash-size (en cuyo caso se escalará cada vez que la tabla crezca), o puede ser un número de punto flotante entre cero y 1. El valor predeterminado para esto El argumento depende de la implementación.
También puede llamar a la función make-hash-table sin argumentos.
Recuperar elementos y agregar elementos a la tabla hash
los gethashLa función recupera un elemento de la tabla hash buscando su clave. Si no encuentra la clave, devuelve nil.
Tiene la siguiente sintaxis:
gethash key hash-table &optional default
donde -
clave: es la clave asociada
tabla hash: es la tabla hash que se buscará
predeterminado: es el valor que se devolverá, si no se encuentra la entrada, que es nulo, si no se especifica.
los gethash La función en realidad devuelve dos valores, el segundo es un valor de predicado que es verdadero si se encontró una entrada y falso si no se encontró ninguna entrada.
Para agregar un elemento a la tabla hash, puede usar el setf función junto con el gethash función.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq empList (make-hash-table))
(setf (gethash '001 empList) '(Charlie Brown))
(setf (gethash '002 empList) '(Freddie Seal))
(write (gethash '001 empList))
(terpri)
(write (gethash '002 empList))
Cuando ejecuta el código, devuelve el siguiente resultado:
(CHARLIE BROWN)
(FREDDIE SEAL)
Eliminar una entrada
los remhashLa función elimina cualquier entrada para una clave específica en la tabla hash. Este es un predicado que es verdadero si hubo una entrada o falso si no la hubo.
La sintaxis de esta función es:
remhash key hash-table
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq empList (make-hash-table))
(setf (gethash '001 empList) '(Charlie Brown))
(setf (gethash '002 empList) '(Freddie Seal))
(setf (gethash '003 empList) '(Mark Mongoose))
(write (gethash '001 empList))
(terpri)
(write (gethash '002 empList))
(terpri)
(write (gethash '003 empList))
(remhash '003 empList)
(terpri)
(write (gethash '003 empList))
Cuando ejecuta el código, devuelve el siguiente resultado:
(CHARLIE BROWN)
(FREDDIE SEAL)
(MARK MONGOOSE)
NIL
La función maphash
los maphash función le permite aplicar una función específica en cada par clave-valor en una tabla hash.
Toma dos argumentos: la función y una tabla hash, e invoca la función una vez para cada par clave / valor en la tabla hash.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(setq empList (make-hash-table))
(setf (gethash '001 empList) '(Charlie Brown))
(setf (gethash '002 empList) '(Freddie Seal))
(setf (gethash '003 empList) '(Mark Mongoose))
(maphash #'(lambda (k v) (format t "~a => ~a~%" k v)) empList)
Cuando ejecuta el código, devuelve el siguiente resultado:
3 => (MARK MONGOOSE)
2 => (FREDDIE SEAL)
1 => (CHARLIE BROWN)
Common LISP proporciona numerosas funciones de entrada y salida. Ya hemos utilizado la función de formato y la función de impresión para la salida. En esta sección, veremos algunas de las funciones de entrada-salida más comúnmente utilizadas proporcionadas en LISP.
Funciones de entrada
La siguiente tabla proporciona las funciones de entrada de LISP más utilizadas:
No Señor. | Función descriptiva |
---|---|
1 | read& flujo de entrada opcional eof-error-p eof-value recursive-p Lee la representación impresa de un objeto Lisp de input-stream, construye un objeto Lisp correspondiente y devuelve el objeto. |
2 | read-preserving-whitespace& opcional in-stream eof-error-p eof-value recursive-p Se utiliza en algunas situaciones especializadas en las que es deseable determinar con precisión qué carácter terminó el token extendido. |
3 | read-line& flujo de entrada opcional eof-error-p eof-value recursive-p Se lee en una línea de texto terminada por una nueva línea. |
4 | read-char& flujo de entrada opcional eof-error-p eof-value recursive-p Toma un carácter de input-stream y lo devuelve como un objeto de carácter. |
5 | unread-char carácter y flujo de entrada opcional Coloca el carácter leído más recientemente del flujo de entrada, al frente del flujo de entrada. |
6 | peek-char& flujo de entrada de tipo peek opcional eof-error-p eof-value recursive-p Devuelve el siguiente carácter que se leerá del flujo de entrada, sin eliminarlo realmente del flujo de entrada. |
7 | listen& flujo de entrada opcional El predicado listen es verdadero si hay un carácter disponible inmediatamente desde el flujo de entrada, y es falso si no. |
8 | read-char-no-hang& flujo de entrada opcional eof-error-p eof-value recursive-p Esto es similar a read-char, pero si no obtiene un carácter, no espera un carácter, sino que devuelve nil inmediatamente. |
9 | clear-input& flujo de entrada opcional Borra cualquier entrada almacenada en búfer asociada con input-stream. |
10 | read-from-string string & opcional eof-error-p eof-value & key: start: end: preserve-whitespace Toma los caracteres de la cadena sucesivamente y construye un objeto LISP y devuelve el objeto. También devuelve el índice del primer carácter de la cadena no leída, o la longitud de la cadena (o, longitud +1), según sea el caso. |
11 | parse-integer cadena y clave: inicio: fin: base: basura permitida Examina la subcadena de la cadena delimitada por: inicio y: fin (predeterminado al principio y al final de la cadena). Omite los espacios en blanco y luego intenta analizar un número entero. |
12 | read-byte flujo de entrada binaria y valor eof-error-p opcional Lee un byte del flujo de entrada binario y lo devuelve en forma de entero. |
Leer entrada desde el teclado
los readLa función se utiliza para recibir entradas desde el teclado. Puede que no necesite ningún argumento.
Por ejemplo, considere el fragmento de código:
(write ( + 15.0 (read)))
Suponga que el usuario ingresa 10.2 desde la entrada STDIN, regresa,
25.2
La función de lectura lee caracteres de un flujo de entrada y los interpreta analizándolos como representaciones de objetos Lisp.
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él:
; the function AreaOfCircle
; calculates area of a circle
; when the radius is input from keyboard
(defun AreaOfCircle()
(terpri)
(princ "Enter Radius: ")
(setq radius (read))
(setq area (* 3.1416 radius radius))
(princ "Area: ")
(write area))
(AreaOfCircle)
Cuando ejecuta el código, devuelve el siguiente resultado:
Enter Radius: 5 (STDIN Input)
Area: 78.53999
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(with-input-from-string (stream "Welcome to Tutorials Point!")
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (read-char stream))
(print (peek-char nil stream nil 'the-end))
(values)
)
Cuando ejecuta el código, devuelve el siguiente resultado:
#\W
#\e
#\l
#\c
#\o
#\m
#\e
#\Space
#\t
#\o
#\Space
Las funciones de salida
Todas las funciones de salida en LISP toman un argumento opcional llamado flujo de salida, donde se envía la salida. Si no se menciona o es nulo, output-stream toma por defecto el valor de la variable * standard-output *.
La siguiente tabla proporciona las funciones de salida de LISP más utilizadas:
No Señor. | Función y descripción |
---|---|
1 | write object & key: stream: escape: radix: base: circle: pretty: level: length: case: gensym: array write object & key: stream: escape: radix: base: circle: pretty: level: length: case: gensym: array: legible: right-margin: miser-width: lines: pprint-dispatch Ambos escriben el objeto en el flujo de salida especificado por: flujo, que por defecto es el valor de * salida-estándar *. Otros valores predeterminados para las variables globales correspondientes configuradas para impresión. |
2 | prin1 objeto y flujo de salida opcional print objeto y flujo de salida opcional pprint objeto y flujo de salida opcional princ objeto y flujo de salida opcional Todas estas funciones generan la representación impresa del objeto en el flujo de salida . Sin embargo, existen las siguientes diferencias:
|
3 | write-to-string object & key : escape: radix: base: circle: pretty: level: length: case: gensym: array write-to-string object & key: escape: radix: base: circle: pretty: level: length: case: gensym: array: legible: right-margin: miser-width: lines: pprint-dispatch prin1-to-string objeto princ-to-string objeto El objeto se imprime de manera efectiva y los caracteres de salida se convierten en una cadena, que se devuelve. |
4 | write-char carácter y flujo de salida opcional Envía el carácter al flujo de salida y devuelve el carácter. |
5 | write-string cadena y flujo de salida opcional y clave: inicio: fin Escribe los caracteres de la subcadena especificada de cadena en el flujo de salida. |
6 | write-line cadena y flujo de salida opcional y clave: inicio: fin Funciona de la misma manera que write-string, pero luego genera una nueva línea. |
7 | terpriy flujo de salida opcional Genera una nueva línea en el flujo de salida. |
8 | fresh-liney flujo de salida opcional genera un salto de línea solo si el flujo no está ya al comienzo de una línea. |
9 | finish-outputy flujo de salida opcional force-outputy flujo de salida opcional clear-outputy flujo de salida opcional
|
10 | write-byte flujo de salida binario entero Escribe un byte, el valor del entero. |
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
; this program inputs a numbers and doubles it
(defun DoubleNumber()
(terpri)
(princ "Enter Number : ")
(setq n1 (read))
(setq doubled (* 2.0 n1))
(princ "The Number: ")
(write n1)
(terpri)
(princ "The Number Doubled: ")
(write doubled)
)
(DoubleNumber)
Cuando ejecuta el código, devuelve el siguiente resultado:
Enter Number : 3456.78 (STDIN Input)
The Number: 3456.78
The Number Doubled: 6913.56
Salida formateada
La función formatse utiliza para producir texto con un formato agradable. Tiene la siguiente sintaxis:
format destination control-string &rest arguments
dónde,
- el destino es salida estándar
- control-string contiene los caracteres que se van a generar y la directiva de impresión.
UN format directive consta de una tilde (~), parámetros de prefijo opcionales separados por comas, dos puntos opcionales (:) y modificadores de signo de arroba (@), y un solo carácter que indica qué tipo de directiva es esta.
Los parámetros de prefijo son generalmente números enteros, anotados como números decimales con signo opcional.
La siguiente tabla proporciona una breve descripción de las directivas de uso común:
No Señor. | Directiva y descripción |
---|---|
1 | ~A Va seguido de argumentos ASCII. |
2 | ~S Va seguido de expresiones S. |
3 | ~D Para argumentos decimales. |
4 | ~B Para argumentos binarios. |
5 | ~O Para argumentos octales. |
6 | ~X Para argumentos hexadecimales. |
7 | ~C Para argumentos de personajes. |
8 | ~F Para argumentos de punto flotante de formato fijo. |
9 | ~E Argumentos exponenciales de punto flotante. |
10 | ~$ Argumentos del dólar y del punto flotante. |
11 | ~% Se imprime una nueva línea. |
12 | ~* El siguiente argumento se ignora. |
13 | ~? Indirección. El siguiente argumento debe ser una cadena y el siguiente una lista. |
Ejemplo
Reescribamos el programa que calcula el área de un círculo:
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(defun AreaOfCircle()
(terpri)
(princ "Enter Radius: ")
(setq radius (read))
(setq area (* 3.1416 radius radius))
(format t "Radius: = ~F~% Area = ~F" radius area)
)
(AreaOfCircle)
Cuando ejecuta el código, devuelve el siguiente resultado:
Enter Radius: 10.234 (STDIN Input)
Radius: = 10.234
Area = 329.03473
Hemos hablado sobre cómo LISP común maneja la entrada y salida estándar. Todas estas funciones funcionan para leer y escribir en archivos de texto y binarios también. En este caso, la única diferencia es que el flujo que usamos no es una entrada o salida estándar, sino un flujo creado con el propósito específico de escribir o leer archivos.
En este capítulo veremos cómo LISP puede crear, abrir, cerrar archivos de texto o binarios para su almacenamiento de datos.
Un archivo representa una secuencia de bytes, no importa si es un archivo de texto o un archivo binario. Este capítulo lo llevará a través de funciones / macros importantes para la administración de archivos.
Abrir archivos
Puedes usar el openfunción para crear un nuevo archivo o para abrir un archivo existente. Es la función más básica para abrir un archivo. sin embargo, elwith-open-file suele ser más conveniente y de uso más común, como veremos más adelante en esta sección.
Cuando se abre un archivo, se construye un objeto de flujo para representarlo en el entorno LISP. Todas las operaciones en la secuencia son básicamente equivalentes a las operaciones en el archivo.
Sintaxis para open la función es -
open filename &key :direction :element-type :if-exists :if-does-not-exist :external-format
dónde,
El nombre de fichero argumento es el nombre del archivo que se abre o se crea.
The keyword arguments specify the type of stream and error handling ways.
The :direction keyword specifies whether the stream should handle input, output, or both, it takes the following values −
:input - for input streams (default value)
:output - for output streams
:io - for bidirectional streams
:probe - for just checking a files existence; the stream is opened and then closed.
The :element-type specifies the type of the unit of transaction for the stream.
The :if-exists argument specifies the action to be taken if the :direction is :output or :io and a file of the specified name already exists. If the direction is :input or :probe, this argument is ignored. It takes the following values −
:error - it signals an error.
:new-version - it creates a new file with the same name but larger version number.
:rename - it renames the existing file.
:rename-and-delete - it renames the existing file and then deletes it.
:append - it appends to the existing file.
:supersede - it supersedes the existing file.
nil - it does not create a file or even a stream just returns nil to indicate failure.
The :if-does-not-exist argument specifies the action to be taken if a file of the specified name does not already exist. It takes the following values −
:error - it signals an error.
:create - it creates an empty file with the specified name and then uses it.
nil - it does not create a file or even a stream, but instead simply returns nil to indicate failure.
The :external-format argument specifies an implementation-recognized scheme for representing characters in files.
For example, you can open a file named myfile.txt stored in the /tmp folder as −
(open "/tmp/myfile.txt")
Writing to and Reading from Files
The with-open-file allows reading or writing into a file, using the stream variable associated with the read/write transaction. Once the job is done, it automatically closes the file. It is extremely convenient to use.
It has the following syntax −
with-open-file (stream filename {options}*)
{declaration}* {form}*
filename is the name of the file to be opened; it may be a string, a pathname, or a stream.
The options are same as the keyword arguments to the function open.
Example 1
Create a new source code file named main.lisp and type the following code in it.
(with-open-file (stream "/tmp/myfile.txt" :direction :output)
(format stream "Welcome to Tutorials Point!")
(terpri stream)
(format stream "This is a tutorials database")
(terpri stream)
(format stream "Submit your Tutorials, White Papers and Articles into our Tutorials Directory.")
)
Please note that all input-output functions discussed in the previous chapter, such as, terpri and format are working for writing into the file we created here.
When you execute the code, it does not return anything; however, our data is written into the file. The :direction :output keywords allows us do this.
However, we can read from this file using the read-line function.
Example 2
Create a new source code file named main.lisp and type the following code in it.
(let ((in (open "/tmp/myfile.txt" :if-does-not-exist nil)))
(when in
(loop for line = (read-line in nil)
while line do (format t "~a~%" line))
(close in)
)
)
When you execute the code, it returns the following result −
Welcome to Tutorials Point!
This is a tutorials database
Submit your Tutorials, White Papers and Articles into our Tutorials Directory.
Closing File
The close function closes a stream.
Structures are one of the user-defined data type, which allows you to combine data items of different kinds.
Structures are used to represent a record. Suppose you want to keep track of your books in a library. You might want to track the following attributes about each book −
- Title
- Author
- Subject
- Book ID
Defining a Structure
The defstruct macro in LISP allows you to define an abstract record structure. The defstruct statement defines a new data type, with more than one member for your program.
To discuss the format of the defstruct macro, let us write the definition of the Book structure. We could define the book structure as −
(defstruct book
title
author
subject
book-id
)
Please note
The above declaration creates a book structure with four named components. So every book created will be an object of this structure.
It defines four functions named book-title, book-author, book-subject and book-book-id, which will take one argument, a book structure, and will return the fields title, author, subject and book-id of the book object. These functions are called the access functions.
The symbol book becomes a data type and you can check it using the typep predicate.
There will also be an implicit function named book-p, which is a predicate and will be true if its argument is a book and is false otherwise.
Another implicit function named make-book will be created, which is a constructor, which, when invoked, will create a data structure with four components, suitable for use with the access functions.
The #S syntax refers to a structure, and you can use it to read or print instances of a book.
An implicit function named copy-book of one argument is also defined that. It takes a book object and creates another book object, which is a copy of the first one. This function is called the copier function.
You can use setf to alter the components of a book, for example
(setf (book-book-id book3) 100)
Example
Create a new source code file named main.lisp and type the following code in it.
(defstruct book
title
author
subject
book-id
)
( setq book1 (make-book :title "C Programming"
:author "Nuha Ali"
:subject "C-Programming Tutorial"
:book-id "478")
)
( setq book2 (make-book :title "Telecom Billing"
:author "Zara Ali"
:subject "C-Programming Tutorial"
:book-id "501")
)
(write book1)
(terpri)
(write book2)
(setq book3( copy-book book1))
(setf (book-book-id book3) 100)
(terpri)
(write book3)
When you execute the code, it returns the following result −
#S(BOOK :TITLE "C Programming" :AUTHOR "Nuha Ali" :SUBJECT "C-Programming Tutorial" :BOOK-ID "478")
#S(BOOK :TITLE "Telecom Billing" :AUTHOR "Zara Ali" :SUBJECT "C-Programming Tutorial" :BOOK-ID "501")
#S(BOOK :TITLE "C Programming" :AUTHOR "Nuha Ali" :SUBJECT "C-Programming Tutorial" :BOOK-ID 100)
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 −
Sr.No. | Function and Description |
---|---|
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 Tutorials Point")
)
(hello)
(in-package dick)
(defun hello ()
(write-line "Hello! This is Dick's Tutorials Point")
)
(hello)
(in-package harry)
(defun hello ()
(write-line "Hello! This is Harry's Tutorials Point")
)
(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 Tutorials Point
Hello! This is Dick's Tutorials Point
Hello! This is Harry's Tutorials Point
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 Tutorials Point")
)
(in-package dick)
(defun hello ()
(write-line "Hello! This is Dick's Tutorials Point")
)
(in-package harry)
(defun hello ()
(write-line "Hello! This is Harry's Tutorials Point")
)
(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 Tutorials Point
Hello! This is Dick's Tutorials Point
Hello! This is Harry's Tutorials Point
*** - EVAL: variable TOM has no value
In Common LISP terminology, exceptions are called conditions.
In fact, conditions are more general than exceptions in traditional programming languages, because a condition 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 −
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)) )
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 erroring 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)
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.
Sr.No. | Function and Description |
---|---|
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.
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))
Cuando ejecuta el código, devuelve el siguiente resultado:
Length of the Box is 10
Breadth of the Box is 10
Height of the Box is 5
Definición de un método de clase
los defmethodmacro le permite definir un método dentro de la clase. El siguiente ejemplo extiende nuestra clase Box para incluir un método llamado volumen.
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(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))
Cuando ejecuta el código, devuelve el siguiente resultado:
Length of the Box is 10
Breadth of the Box is 10
Height of the Box is 5
Volume of the Box is 500
Herencia
LISP le permite definir un objeto en términos de otro objeto. Se llamainheritance.Puede crear una clase derivada agregando características nuevas o diferentes. La clase derivada hereda las funcionalidades de la clase principal.
El siguiente ejemplo explica esto:
Ejemplo
Cree un nuevo archivo de código fuente llamado main.lisp y escriba el siguiente código en él.
(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))
Cuando ejecuta el código, devuelve el siguiente resultado:
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