Sei sulla pagina 1di 158

Visual LISP para AutoCAD 2000

Apuntes para un libro en preparacin

Estos apuntes, que forman parte de un libro en


preparacin, fueron desarrollados originalmente
como material de estudio para el curso dictado como
parte del programa de estudios para la Maestra en
Computacin e Informtica en la Facultad de
Ciencias Exactas , Universidad Nacional del Nordeste
en Corrientes, Argentina.
CORRIENTES, 7 de junio de 1999
SANTANDER, 19 de septiembre de 1999
Reinaldo Togores Fernndez, Profesor Asociado.
Departamento de Ingeniera Geogrfica y Tcnicas
de Expresin Grfica,
Universidad de Cantabria.
Santander, Espaa.
Instructor de Diseo Asistido por Ordenador del
Instituto de Formacin y Estudios Sociales.
NDICE DE CONTENIDOS
AGRADECIMIENTOS
INTRODUCCIN

LISP: PARADIGMA DEL ESTILO DE


PROGRAMACIN FUNCIONAL

PRIMERA PARTE:
EL ENTORNO DE DESARROLLO VISUAL LISP

Esta seccin se encuentra en preparacin.


1. VISUAL LISP
2. EL ENTORNO DE DESARROLLO VISUAL LISP
o
o
o
o

El Trabajo con Visual LISP y AutoCAD


Barra de Mens
Las Barras de Herramientas
La Consola Visual LISP

El Editor Visual LISP


Barras de Herramientas
Men Contextual
Teclas Rpidas

SEGUNDA PARTE:
TCNICAS FUNDAMENTALES DE LA PROGRAMACIN
LISP
1. TIPOS DE DATOS

TOMOS
o TOMOS SIMBLICOS (S-ATOMS)
o CONSTANTES
NMEROS
CADENAS DE TEXTO
o LISTAS Y CONSES
LISTAS DE UN NIVEL
LISTAS ANIDADAS
LISTAS DE ASOCIACIN (A-LIST)
LA LISTA VACA (NIL)
o FUNCIN TYPE: EXAMEN DEL TIPO DE DATO
TIPOS DE DATOS LISP
TIPOS DE DATOS AUTOCAD
TIPOS DE DATOS ACTIVE-X
2. FUNCIONES
o FUNCIONES PRIMITIVAS
OPERADORES ARITMTICOS
FUNCIONES DE ACCESO A LISTAS
CONSTRUCCIN DE LISTAS
PROCESAMIENTO DE LISTAS
TRATAMIENTO DE CADENAS
TRATAMIENTO DE CADENAS CON VLISP
o FORMAS ESPECIALES
o FUNCIONES DEFINIDAS POR EL USUARIO
DEFUN: NUEVAS FUNCIONES PARA LA
EXTENSIN DE LISP
REALES A ENTEROS: TRUCAMIENTO
O REDONDEO
FUNCIONES TRIGONOMTRICAS
LAMBDA
FUNCTION
LOAD
o

3. ESTRUCTURAS DE CONTROL

PREDICADOS GENERALES
o PREDICADOS ARITMTICOS
o OPERADORES LGICOS
o OPERADORES LGICOS BINARIOS
Nmeros Binarios
Funcin LSH
Funcin ~ (NOT lgico binario)
Funcin LOGAND
CONVERSIN ENTRE BINARIOS Y
DECIMALES (I)
CONVERSIN ENTRE BINARIOS Y
DECIMALES (II)
Funcin LOGIOR
Funcin BOOLE
o PREDICADOS DEFINIDOS POR EL USUARIO
o ESTRUCTURAS CONDICIONALES
4. FUNCIONES RECURSIVAS E ITERATIVAS
o FUNCIONES RECURSIVAS
EXTRACCIN DE LOS VRTICES DE UNA
POLILNEA
o FUNCIONES ITERATIVAS
REPETICIN UN NMERO DETERMINADO
DE VECES
ITERACIONES SOBRE ELEMENTOS DE
UNA SECUENCIA
CICLOS DEPENDIENTES DE UNA
CONDICIONAL
o FUNCIONES DE MAPEADO SOBRE SECUENCIAS
EXTRACCIN DE LOS VRTICES DE UNA
POLILNEA
Una solucin ms eficaz.
o CUNDO RECURSIN Y CUNDO
ITERACIN?
o

TERCERA PARTE:
ACCESO A LA BASE DE DATOS GEOMTRICA

Esta seccin se encuentra en preparacin.

ACCESO A LA LISTA DE DATOS DE OBJETO

EXTRACCIN DE LISTAS DE DATOS DE


OBJETO
o TRANSFORMACIN DE LOS DATOS DE OBJETO:
CONVERSIN DE POLILNEAS EN
SPLINES
PROGRAMA PL2SP.LSP
EJEMPLOS DE LA UTILIZACIN DE ENTMAKE
o DEFINICIN DE BLOQUES
o DEFINICIN DE CAPAS
SISTEMAS DE COORDENADAS
o EJEMPLO DE TRANSFORMACIN ENTRE SISTEMAS
DE COORDENADAS:
CONVERSIN DE POLILNEAS 3D EN 2D
o

ANEXO A

TABLA DE FUNCIONES VISUAL LISP


NOTA: Esta tabla est en formato PDF. Para verla es necesario
el Acrobat READER.
Para descargar el Acrobat Reader 4.0 pulse
aqu

ANEXO B
ARCHIVOS LISP Y DCL SUMINISTRADOS CON AUTOCAD:

Versin
Versin
Versin
Versin
Versin
Versin
Versin

2.5
10
11
12
13
14
2000

ANEXO C
EJEMPLO DE MEN PERSONALIZADO (R14):

Mens AutoCAD y Bonus Personalizados


Descarga de ambos en formato ZIP
ANEXO D

UTILIDADES VARIAS:

3DTHD.LSP - Programa para dibujar roscas mediante


slidos 3D
ANEXO E

Enlaces conocidos a este sitio WEB


Inicio | Continuar...
1999, Reinaldo Togores.
El cdigo publicado es nuestro, salvo en los casos en
que as se expresa.
Todos los derechos sobre los programas que citamos
son de la exclusiva propiedad de sus autores. En los
casos en que as lo requiere el autor hemos incluido
las respectivas informaciones sobre el copyright.
El cdigo que publicamos bajo nuestro nombre slo
puede ser utilizado con fines no comerciales,
mencionando siempre al autor y a la obra de donde
se ha tomado.
/hide script from old browsers document.write( "
Actualizado "+ document.lastModified ); //end hiding
contents --->
FastCounter by bCentral

curso
AGRADECIMIENTOS:

En primer trmino a mis compaeros del Departamento de


Ingeniera Geogrfica y Tcnicas de Expresin Grfica de la
Universidad de Cantabria por el apoyo brindado para la
preparacin de este curso, y sobre todo a los profesores
Milagros Canga y Csar Otero, sin cuyo aporte hubiera sido
muy difcil cumplir esta tarea. Tambin a la direccin del
Instituto de Formacin y Estudios Sociales en Cantabria
por las facilidades brindadas para la inclusin de este curso
en una apretada agenda de compromisos. Por su gentil
acogida y dedicacin, a los profesores y alumnos de la
Maestra en Informtica y Computacin de la Facultad de
Ciencias Exactas, Universidad Nacional del Nordeste, en
Corrientes, Argentina y muy especialmente a los profesores
David La Red Martnez y Guido Pace.
FUENTES:

Queremos reconocer nuestra deuda hacia todos aqullos que


de manera tan desinteresada brindan su experiencia a travs
de Internet y en los grupos de noticias especializados. An
siendo injusto por las inevitables omisiones quiero mencionar
a Reini Urban cuya Pgina AutoCAD y cuyo FAQ AutoLISP
son obligada referencia en cualquier trabajo de este tipo, a
Vlad Nesterovsky, Dennis Shinn, Tony Tanzillo, Jon
Fleming y Richard D. Howard. A The Association of Lisp
Users(ALU) y a los autores de las muchas contribuciones
tericas sobre Inteligencia Artificial y tutoriales LISP referidas
desde su sitio WEB, especialmente los de Ray Dougherty y
Mark Schwarz de la NYU, del ELM Research Group, de
Collin Allen y Maneesh Dhagat. para los estudiantes de
Texas A&M y de Eduardo Villamil en Tulane University, de
todos los cuales he tomado ideas y ejemplos de cdigo que he
debido adaptar al entorno AutoLISP. No quiero terminar sin
hacer mencin a dos libros esclarecedores que tambin cito
profusamente: On LISP, de Paul Graham, verdadera
revelacin en cuanto a las potencialidades de este poco
conocido lenguaje de programacin y Common LISP: The
Language, 2nd Edition (CLTL2) de Guy Steele, que
contiene las especificaciones del lenguaje. Otro libro que nos
ha sido de inapreciable valor para la comprensin de la

jeraqua de objetos ActiveX de Autocad es el recin publicado


AutoCAD 2000 VBA Programmer's Reference, de Joe Sutphin.

INTRODUCCIN:

LISP se encuentra entre los ms antiguos lenguajes de


programacin de alto nivel an en uso generalizado. Fue
desarrollado alrededor de 1958 por John McCarthy. La idea de
LISP surgi a partir de un sistema lgico llamado "lambda
calculus'' desarrollado por Alonzo Church. Existen diversas
variantes (o dialectos) de LISP, entre las cuales se encuentran
Scheme, T, etc. LISP lleg a ser fundamental como lenguaje
de programacin para las investigaciones de Inteligencia
Artificial, y sigue an hoy siendo uno de los ms utilizados en
este campo. En la dcada de los '80 se intent estandardizar
el lenguaje. Como resultado surgi el Common LISP cyas
especificaciones se recogen en Common LISP: The
Language, 2nd Edition (CLTL2). Common LISP es
actualmente el dialecto ms difundido y la base para el
desarrollo de numerosas implementaciones.
Las razones para ello se encuentran en el hecho de poseer
una de las formas de sintaxis menos restrictivas entre los
lenguajes de alto nivel. Esto facilita su aprendizaje, al ser
muy corto el nmero de estructuras y funciones que el
estudiante debe conocer para llegar a dominar las tcnicas de
programacin en este lenguaje. De hecho, este curso se
propone la utilizacin de un subconjunto de las muchas
funciones disponibles para con ellas examinar las tcnicas que
hacen de LISP un lenguaje tan especial.
LISP: PARADIGMA DEL ESTILO DE PROGRAMACIN
FUNCIONAL

Una de Las caractersticas de LISP es la posibilidad de tratar


las propias funciones como datos. En LISP, funciones e incluso
programas enteros pueden ser utilizados directamente como
entrada a otros programas o subrutinas. En esto el prototipo

para la concepcin del lenguaje ha sido la estructura de las


funciones matemticas. Todos sabemos cmo resolver una
expresin del tipo (8 * ((17 + 3) / 4)). Primero hallaramos el
resultado de 17 + 3, que entonces dividiramos entre 4, para
el resultado multiplicarlo por 8. Es decir, que iramos
resolviendo los parntesis ms interiores y pasando los
resultados a las operaciones descritas en los parntesis que
los contienen.
(* 8 (/ (+ 3 17) 4)) sera la funcin LISP equivalente.
*, / y + son nombres de funciones LISP. Los nmeros en (+ 3
17) son los argumentos que se pasan a la funcin '+'. Pero en
(/ (+ 3 17) 4) a la funcin '/' se le est pasando un
argumento numrico 4, pero tambin (+ 3 17), otra funcin
con dos argumentos numricos. Esta es la esencia de un
lenguaje de programacin funcional y por eso decimos que
LISP lo es. "Programacin funcional significa, seg Graham
(On Lisp, pg. 28), escribir programas que operan a base de
devolver valores en lugar de producir efectos colaterales.
Estos efectos colaterales incluyen cambios destructivos en los
objetos y la asignacin de variables (con setq, por ejemplo)."
Sigue explicando Graham (pg. 31) que "una funcin
destructiva es una que puede alterar los argumentos que se
le pasan. Slo unos pocos operadores LISP estn pensados
para producir efectos colaterales. En general, los operadores
propios del lenguaje estn pensados de manera tal que se
invoquen para obtener los valores que devuelven. Nombres
como sort (vl-sort), remove (vl-remove) o substitute (subst)
no deben llamarnos a engao. Si usted quiere efectos
colaterales, utilice setq sobre el valor devuelto. Esta misma
regla sugiere" -sigue explicando Graham- "que algunos
efectos colaterales son inevitables. Tener la programacin
funcional como ideal no implica que los programas nunca
debieran tener efectos colaterales. Slo quiere decir que no
deben tener ms de los necesarios."
Esta caracterstica de la programacin funcional no es
arbitraria. Citando de nuevo a Graham:
Los programadores LISP no adoptaron el estilo funcional por
razones meramente estticas. Lo usan porque facilita su
trabajo. En el entorno dinmico de LISP, los programas

funcionales pueden ser escritos a una velocidad poco usual, y


a la vez, pueden ser inusualmente confiables.
En LISP es comparativamente fcil el depurar los programas.
Una gran cantidad de informacin se encuentra disponible en
tiempo de ejecucin, lo que ayuda en el rastreo de los
errores. Pero an ms importante es la facilidad con la que
pueden probarse los programas. No es necesario el compilar
el programa para probar su funcionamiento como un todo.
Podemos probar las funciones individualmente, llamndolas
desde el nivel superior del evaluador.
Esta comprobacin de carcter incremental es tan valiosa que
el estilo de programacin LISP ha evolucionado para
aprovecharla. Los programas escritos en un estilo funcional
pueden ser comprendidos una funcin a la vez, y desde el
punto de vista del lector, esta es su principal ventaja. Sin
embargo, el estilo funcional se adapta perfectamente a la
comprobacin incremental: los programas escritos en este
estilo pueden ser tambin probados una funcin a la vez.
Cuando una funcin ni examina ni altera el estado exterior,
los errores se harn aparentes de inmediato. Una funcin as
diseada slo puede afectar el mundo exterior a travs de los
valores que devuelve. En la medida que estos valores sean los
esperados, podemos confiar en el cdigo que los produjo.
Los programadores LISP experimentados de hecho disean
sus programas de manera que puedan ser fcilmente
probados:
1. Tratan de aislar los efectos colaterales en unas
pocas funciones, de manera que la mayor parte del
programa pueda ser escrito en un estilo puramente
funcional.
2. Si una funcin debe producir efectos colaterales,
tratan de que al menos posea una interfaz
funcional.
3. Le dan a cada funcin un propsito nico y bien
definido
Cuando acaba de escribirse una funcin, pueden probarla
sobre una seleccin de casos representativos, y una vez
hecho esto pasar a la prxima funcin.
En LISP, como en cualquier otro lenguaje, el desarrollo se
lleva a cabo en ciclos de escritura y comprobacin. Pero en

LISP el ciclo es muy corto: funciones aisladas, e incluso


partes de funciones. Y si comprobamos todo a medida que lo
escribimos, sabremos dnde buscar cuando se produzca un
error: en lo ltimo que se escribi.
Graham, On Lisp, pg. 37 y 38.
Lisp mas all de AutoCAD

Hay implementaciones de LISP para uso en el desarrollo de


aplicaciones de todo tipo. El lenguaje se ha normalizado con
el nombre de Common LISP (norma ANSI).
Existen entornos de desarrollo disponibles muchas veces
como software gratuito a travs de internet. Para ms
informacin se recomienda acceder a los siguientes sitios
WEB*:
Compiladores y entornos de desarrollo Common LISP para
WINDOWS:

Xanalys LispWorks
Allegro CL
Corman Common Lisp
CLISP

Los primeros tres son productos comerciales, pero todos


ofrecen versiones gratuitas de evaluacin perfectamente
adecuadas para el aprendizaje del lenguaje.
CLISP es totalmente gratis (GPL).
LispWorks es especialmente recomendable por su claro
entorno de desarrollo (IDE), la capacidad de construir
fcilmente aplicaciones con una interfaz grfica de usuario
(GUI) y la licencia de evaluacin que permite el utilizar el
producto por tanto tiempo como se desee, con slo unas
limitaciones de menor entidad. Le acompaa una muy
completa referencia en formato HTML y PDF.
Allegro CL posee herramientas para el desarrollo de
interfaces grficas mucho ms completas, pero la licencia de
evaluacin debe ser renovada cada mes.
Corman LISP slo brinda la posibilidad de utilizar el IDE
como evaluacin durante un mes, aunque el compilador en s

es gratuito y posee una consola LISP tambin gratuita. Para


Corman Common Lisp el profesor Reini Urban ha
implementado la posibilidad de su ejecucin desde el entorno
AutoCAD lo que que pudiera sealar un camino de desarrollo
interesante para el futuro.
Tutoriales en la Red:
El libro de David Touretzky "Common Lisp: A Gentle
Introduction to Symbolic Computation", que est
disponible en formato PDF.
El libro de David Lamkins "Successful Lisp: How to
Understand and Use Common Lisp" en formato html.
La Common LISP HyperSpec, de Kent Pitman, que no es un
tutorial, sino la referencia definitiva del lenguaje. Cortesa de
la casa que comercializa LispWorks.
El libro de Guy Steele "Common LISP, the language. 2nd
Edition", ms conocido como CLTL2, aunque anterior a la
norma ANSI, an merece ser ledo.
Si se trata de comprar un libro, lo recomendable sera
comenzar, ya sea con el de Paul Graham "ANSI Common
Lisp" o con el de Stephen Slade "Object-Oriented
Common LISP".
Despus, el PAIP ("Paradigms of Artificial Intelligence
Programming") de Peter Norvig es una lectura obligada.
En la Web sera necesario visitar el CLiki y la pgina de ALU
(Association of LISP Users) para ms enlaces de inters.
Un caso particular es el del Corman Common Lisp, para el
que Reini Urban ha implementado la posibilidad de su
ejecucin desde el entorno AutoCAD y que pudiera sealar un
camino de desarrollo interesante para el futuro. Tambin
existen utilidades para la transferencia de programas
AutoLISP-XLISP desarrolladas por Tony Tanzillo.
* Fuente: Dr. Edmund Weitz (edi@agharta.de)
posting al newsgroup comp.lang.lisp Fecha: 200109-28 03:38:20 PST
PARA MUESTRA...

Como una muestra de la capacidad de sntesis y abstraccin a


la que podemos acceder con LISP (y una buena cuota de
ingenio) reproducimos este pequeo problema planteado a
manera de acertijo hace unos das por Vladimir Nesterovski
en el grupo de noticias autodesk.autocad.customization, y
la solucin propuesta otro maestro, Tony Tanzillo:
Hola todos, os propongo algo:
crear una funcin que para una lista de puntos
devuelva un par de puntos con los valores mnimos
y mximos (una suerte de "caja de abarque"), que
funcione para puntos n-dimensionales y que no
emplee LAMBDA o SETQ.
Debe ser simple tambin. :)
Por ejemplo, para '( (1 2 2) (2 5 4) (3 1 2) )
devolvera '( (1 1 2) (3 5 4) ).
Pasadlo bien, :-)
-Vlad
Y la respuesta de Tony Tanzillo:
(defun extents (plist)
(list (apply 'mapcar (cons 'min plist))
(apply 'mapcar (cons 'max plist))))
En dos lneas de cdigo resuelta una funcin que explicada en
trminos de programacin ms convencionales, recibir dos
matrices de dimensiones variables n x m y devolver una
matriz conteniendo los mximos y mnimos para cada uno de
los trminos de las matrices recibidas. La funcin EXTENTS
recibe como argumento una lista de listas y devuelve otra, sin
recurrir en ningn momento a la creacin de variables como
almacenaje intermedio. Por otra parte el argumento original
permanece inalterado, es decir que se trata de una funcin no
destructiva.
Esto a manera de muestra de lo que trataremos de exponer
de aqu en adelante.

Visual LISP

LISP fu inicialmente fue desarrollado como un lenguaje


interpretado, aunque las modernas versiones cuentan
siempre con un compilador que transforma el cdigo fuente
en lenguaje de mquina optimizado. Esta compilacin puede
ejecutarse de manera inmediata al cargar en el entorno de
desarrollo el cdigo fuente del programa, lo que facilita el
desarrollo al disponer de una evaluacin de manera
inmediata. Para acceder a este entorno, en el caso del Visual
LISP, se teclea desde la lnea de comando de AutoCAD las
instrucciones VLISP VLIDE (esta ltima para compatibilidad
con el Visual LISP de la versin 14). Las instrucciones LISP se
introducen para su evaluacin en una ventana especial
conocida como la Consola Visual LISP. Si no est a la vista, se
puede abrir esta ventana pulsando el botn de la barra de
herramientas.

El cursor que aparece junto al smbolo _$ indica que le


sistema est listo para recibir las expresiones LISP del
usuario. La imagen anterior muestra el resultado de evaluar
una expresin usando funciones aritmticas. La evaluacin se
produce al pulsar <INTRO>. Una vez impreso el resultado
aparece de nuevo el smbolo _$ indicando que el sistema est
listo para recibir una nueva expresin. Este ciclo que se
desarrolla en el intrprete se conoce como bucle de lecturaevaluacin-impresin (read-eval-print loop). Esto significa
que el intrprete lee lo que se ha tecleado, lo evala y
entonces imprime el resultado antes de quedar listo para la
nueva expresin. Al uso de la consola dedicaremos una
seccin especfica de este curso.

El entorno de desarrollo (IDE) Visual LISP cuenta adems con


un Editor especializado y una serie de medios para la
depuracin de los programas muy superiores a los que
estaban disponibles en el viejo AutoLISP.
No obstante, estas lecciones podrn ser seguidas utilizando
cualquier versin de AutoLISP. Se ha tratado de sealar
cuando se est hablando de funciones o modos de operacin
propios del Visual LISP que noi estn disponibles en el
entorno AutoLISP.
Hay otras implementaciones de LISP para uso general
disponibles muchas veces como software gratuito a travs de
internet. Para ms informacin se recomienda acceder a los
siguientes sitios WEB:
AutoCAD-AutoLISP info+tools Pgina AutoCAD/AutoLISP
de Reini Urban.
The Association of Lisp Users Pgina WEB de la Asociacin
de Usuarios de LISP.
Un caso particular es el del Corman Common Lisp, para el
que Reini Urban ha implementado la posibilidad de su
ejecucin desde el entorno AutoCAD y que pudiera sealar un
camino de desarrollo interesante para el futuro. Tambin
existen utilidades para la transferencia de programas
AutoLISP-XLISP desarrolladas por Tony Tanzillo.

EL ENTORNO DE DESARROLLO VISUAL LISP

Visual LISP (VLISP) representa una renovacin de LISP para


AutoCAD, actualizndolo para incluir prestaciones que ya son
normales en los modernos dialectos de LISP que se ajustan a
la normativa COMMON LISP. An sin llegar a ser totalmente
compatible con esta normativa, es significativo el incremento
de su potencia como lenguaje de programacin.

Es particularmente til la posibilidad que se incorpora para la


interaccin con la jerarqua de objetos de la aplicacin
mediante la interfaz ActiveX Automation de Microsoft, y la
posibilidad de responder a eventos mediante la
implementacin de funciones diseadas como reactores.
Como herramienta de desarrollo se aporta un Entorno de
Desarrollo Integrado (IDE) que incluye un compilador y varias
utilidades para la depuracin.
El IDE Visual LISP incluye:

Comprobador de Sintaxis que reconoce secuencias


AutoLISP errneas y el uso incorrecto de los argumentos
en llamadas a las funciones primitivas del lenguaje.
Compilador de Ficheros que incrementa la velocidad de
ejecucin y constituye una plataforma de distribucin
que brinda seguridad al cdigo fuente.
Depurador de Fuentes, diseado especficamente para
AutoLISP, que permite la ejecucin paso a paso del
cdigo fuente en una ventana mientras se observan
simultneamente los resultados obtenidos en la pantalla
grfica de AutoCAD.
Editor de Programacin que emplea la codificacin por
color para LISP y DCL, as como otras caractersticas de
apoyo sintctico.
Formateo LISP automtico que redistribuye las lneas de
cdigo y las identa para facilitar la lectura de los
programas.
Amplias caractersticas de Inspeccin y Vigilancia
(Watch) que permiten el acceso en tiempo real a los
valores de las expresiones y las variables, y que pueden
ser empleadas tanto para datos LISP como para objetos
grficos de AutoCAD.
Ayuda sensible al contexto sobre las funciones AutoLISP
y una ventana Apropos para bsqueda de nombres de
smbolos.
Sistema de Administracin de Proyectos que facilitan el
mantenimiento de aplicaciones con mltiples ficheros
fuente.
Empaquetado de los ficheros AutoLISP compilados en un
nico mdulo de programa.

Capacidad para guardar y recuperar la configuracin del


Escritorio para reutilizar la distribucin de ventanas de
cualquier sesin anterior de VLISP.
Consola Visual LISP Inteligente que permite un nuevo
nivel de interaccin del usuario, con funciones que
amplan las de la ventana de texto habitual de AutoCAD.

El Trabajo con Visual LISP y AutoCAD

VLISP posee su propia ventana de aplicacin distinta de la de


AutoCAD, pero no puede ejecutarse de manera
independiente. Para acceder al IDE Visiual LISP, antes deber
haberse iniciado una sesin de AutoCAD.
Iniciar Visual LISP

Como se dijo antes, Debe haberse iniciado una sesin de


AutoCAD. Esta sesin puede contener slo un dibujo vaco, o
pueden estar abiertos dibujos cuyo contenido se desee
procesar.
Para activar el IDE VLISP tenemos tres opciones:

Seleccionar del men


Herramientas>AutoLISP>Editor Visual LISP
Teclear en la lnea de comandos: VLISP
Nota: Hemos encontrado al menos en una
versin localizada espaola que el comando
VLIDE no es reconocido por el sistema. La
Ayuda de esa misma versin aeala como
alternativa el comando VISUALLISPIDE, que
tampoco es reconocido. En estos casos siempre
se puede recurrir al comando VLIDE, descrito
en el punto siguiente.
La versin anterior de Visual LISP utilizaba con
los mismos fines el comando VLIDE, que sigue
siendo reconocido por la versin 2000. De
hecho, internamente la llamada de AutoCAD al
IDE Visual LISP se realiza mediante este
comando, que veremos aparecer en la lnea de
comandos cada vez que se cambie a ese
entorno.

La Ventana de la Aplicacin

Al iniciarse Visual LISP pasa a primer plano la siguiente


ventana de aplicacin:

Puede seleccionar cada parte de la ventana para una breve


descripcin.

Barra de Mens

Asumimos que el lector est familiarizado con el uso de


mens desplegables en AutoCAD u otras aplicaciones. Slo
cabra destacar que stos mens son sensibles al contexto en
que se utilizan. Es decir, que algunas opciones que pueden
estar activas si se abre la ventana del Editor pueden no
estarlas si el foco se encuentra en la Consola o en la ventana
de TRACE.
Las funciones de la aplicacin se distribuyen entre los mens
desplegables de la siguiente manera

FILE
Creacin de nuevos ficheros de programas abiertos para
su edicin
Apertura de ficheros existentes
Guardar los cambios efectuados
Compilar aplicaciones Visual LISP
Imprimir los ficheros de programas
EDIT
Copiar y Pegar texto
Deshacer el ltimo cambio en el Editor o la ltima
funcin ejecutada desde la Consola
Seleccionar texto en el Editor o la Consola
Comprobar el cierre de parntesis
Recuperar funciones ejecutadas desde la Consola
SEARCH
Buscar y Reemplazar texto
Colocar marcadores de referencia (bookmarks) y
navegar en el texto utilizando estos marcadores.
VIEW
Buscar y mostrar el valor de variables y smbolos en su
cdigo AutoLISP.
PROJECT
Trabaja con los proyectos y la compilacin de programas
DEBUG
Establecer y quitar puntos de ruptura en los programas
Ejecutar programas paso a paso comprobando el estado
de las variables y el valor devuelto por las expresiones.
TOOLS
Establecer las opciones para el formateado del texto y
varias otras opciones del entorno, tales como la
ubicacin de ventanas y barras de herramientas.
WINDOW
Organiza, abre y cierra ventanas en el IDE.
HELP
Pues eso, la Ayuda en lnea.

Las Barras de Herramientas

Visual LISP dispone de cinco Barras de Herramientas que


pueden activarse/desactivarse desde el men
View>Toolbars... que abre el siguiente dilogo:

Estas cinco Barras de Herramientas contienen las opciones u


comandos esenciales del IDE, facilitando el acceso a los
mismos.

Contiene las herramientas usuales de Crear Nuevo,


Abrir, Guardar, Imprimir, Cortar, Copiar, Pegar, Deshacer,
Rehacer y por ltimo un acceso a la fucin Apropos que
sirve para completar el texto buscando una correlacin
de una subcadena con nombres de funciones, etc.
Incluye las funciones de Buscar, Buscar y Reemplazar.
Adems una casilla de lista desplegable donde se
guardan los trminos anteriormente buscados durante la
sesin de trabajo, lo que permite repetir una busqueda
con ms facilidad, cosa que se hace con la herramienta
situada a la derecha de la casilla. Por ltimo incluye una
serie de herramientas para navegar dentro del texto
mediante marcadores, que se introducen con la
herramienta de la izquierda, se avanza o retrocede con
las dos siguientes y se eliminan con la ltima.
La barra Tools (Herramientas) opera slo con la ventana
del Editor activa. Sus funciones son, de izquierda a
derecha: cargar el cdigo del Editor para su ejecucin

desde la Consola, cargar slo el cdigo seleccionado,


comprobar la sintaxis de todo el contenido de la ventana
del Editor, o con la siguiente, comprobar slo lo
seleccionado. Para formatear el texto se utilizan los
prximos dos botones, el primero para todo el editor y el
segundo slo para el textoseleccionado. Los dos
siguientes botones sirven para marcar como coimentario
el texto seleccionado o para desmarcarlo. Y por
supuesto, el ltimo se trata de la Ayuda en lnea.
Los tres primeros botones de esta barra determinan la
accin al encontrar un punto de ruptura durante la
evaluacin. El primero entra en las expresiones anidadas
posteriores al punto de ruptura, evalundolas desde la
ms interior. El segundo evala esta expresin y se
detiene antes de la siguiente para de nuevo decidir si se
quiere entrar a evaluar las expresiones anidadas. El
tercer botn contina hasta el final de la funcin en
curso y entonces cuando se detiene de nuevo la
evaluacin.
El segundo tro de botones tene que ver con las acciones
a tomar cuando se produce una ruptura del flujo de
ejecucin a causa de un error, o de que se alcance un
punto de ruptura prefijado dentro del programa. Aunque
es un tema que se explicar ms adelante, cabe decir
ahora que estos estados de suspensin en la ejecucin
del programa se utilizan para examinar los valores
asumidos por las variables, cambiarlos si es preciso, etc.
El primer botn (Continue) permite terminar con esta
pausa y continuar la ejecucin normal del programa. El
segundo botn (Quit) permite abandonar el nivel de
evaluacin actual (pueden superponerse varios ciclos de
evaluacin si se producen varios errores durante la
depuracin) y pasar al nivel de ms arriba. Y el tercer
botn (Reset) pasa el control de la ejecucin
directamente al nivel superior (Top Level).
El tercer grupo de botones incluye otras tiles
herramientas de depuracin. El botn Toggle Breakpoint

permite aadir un nuevo punto de ruptura en el


programa, situado en la posicin actual del cursor. El
segundo botn (Add Watch) da acceso al dilogo que
permite seleccionar un nombre de variable para
observar sus resultados durante la ejecucin. Estos
resultados se exhiben en una ventana especial, la
ventana Watch.
El botn Last Break resalta en la ventana del editor la
expresin que dio origen a la ltima ruptura. En caso de
error, de esta manera se detecta de inmediato dnde se
produjo ste.
El ltimo botn no es realmente un botn de comando.
Sirve simplemente para indicar si la interrupcin actual
se encuentra antes o despus de la expresin.
El primer botn sirve para poner en primer plano la
ventana de aplicacin de AutoCAD. El segundo botn
abre un men donde podemos seleccionar la ventana del
IDE Visual LISP que deseamos poner en primer plano.
Esto se hace necesario pues podemos tener abiertas de
manera simultnea un gran nmero de programas y
puede no der fcil localizar aqulo que queremos.
El tercer botn traslada el foco a la Consola de Visual
LISP. El siguiente permite activar la caracterstica de
Inspeccin (Inspect). Inspect permite examinar y
modificar objetos AutoLISP as como AutoCAD. La
herramienta Inspect crea una ventana separada para
cada objeto sometido a inspeccin.
La siguiente herramienta (Trace Stack) necesita
explicaciones que se salen del marco de esta
introduccin. Baste decir que nos permite acceder a la
memoria de pila donde se guardan las llamadas a
funcin. Puede invocarse en un momento de suspensin
en la ejecucin de un programa y permite mediante un
men contextual acceder a datos relacionados con la
operacin del programa.
El botn que le sigue (Symbol Service) est diseado para
simplificar el acceso a las distintas utilidades de

depuracin relacionadas con smbolos. Podemos resaltar


cualquier nombre de smbolo en el Editor y al pulsar
sobre este botn se abrir la ventana Symbol Service
donde se muestra el valor vinculado. Este valor se puede
cambiar directamente en esta ventana. Adems tiene
una barra de herramientas que permiten otros procesos
con el smbolo seleccionado.
El siguiente botn permite abrir la ventana Apropos que
describimos en detalle ms adelante
Y por ltimo un botn que permite acceder a la ventana
Watch.

La Consola Visual LISP

Aunque parecida a la ventana de texto de AutoCAD en el


hecho de que se puden introducir funciones para evaluarlas y
obtener el resultado en pantalla, la Consola es una
herramienta de mucha mayor potencia y existen varias
diferencias en su manera de operar que es importante tener
en cuenta.
Por ejemplo, para conocer el valor asociado a un smbolo no
es necesario, como en AutoCAD, precederlo de un signo de
admiracin <!>. Basta teclear el nombre de la variable y

pulsar <INTRO>. En la Consola se emiten una serie de


mensajes de diagnstico durante la ejecucin de las funciones
y si se encuentra un error interrumpe la ejecucin y habilita
un nuevo nivel de evaluacin donde podemos ensayar
cambios en valores de variables y realizar pruebas para
detectar los problemas existentes. De producirse un nuevo
error, se habilita un nuevo nivel y as sucesivamente, hasta
que decidamos regresar al nivel superior. Las baras de
desplazamiento de la consola nos permiten revisar los
resultados anteriores.
Las prestaciones ms importantes de la Consola se resumen a
continuacin:

Evaluar expresiones AutoLISP y mostrar el resultado


devuelto por dichas expresiones.
Introducir expresiones AutoLISP en lneas mltiples
pulsando para el cambio de lne la combinacin <CTRL>
+ <INTRO>. Pulsar slo <INTRO> provocara la
evaluacin de la expresin tecleada hasta entonces.
Evaluar mltiples expresiones a la misma vez.
Copiar y transferir texto entre las ventanas de la
Consola y el Editor. La mayor parte de los comandos de
texto estn disponibles tambin en la Consola.
Recuperar expresiones tecleadas anteriormente en la
Consola, pulsando la tecla <TAB>. Pulsando esta tecla
varias veces se van recuperando las expresiones
anteriores. Para realizar el ciclo en sentido inverso puede
utilizarse la combinacin <SHIFT> + <TAB>.
La tecla <TAB> tambin permite realizar una bsqueda
de carcter asociativo a travs del conjunto de
expresiones anteriores. Si se quiere buscar anteriores
expresiones de creacin de variables bastara teclear
(SETQ y entonces pulsar <TAB>, con lo que se ira
directamente a la ltima expresin tecleada que
comenzaba as. Para realizar el ciclo en sentido inverso
aqu tambin puede utilizarse la combinacin <SHIFT>
+ <TAB>.
Pulsando <ESC> se elimina cualquier texto a
continuacin del smbolo (prompt) del evaluador.

Pulsando <SHIFT> + <ESC> abre una nueva Consola,


dejando el texto escrito en la ventana de Consola
anterior sin evaluar.
Al pulsar el botn derecho del ratn en cualquier punto
de la Consola o tecleando <SHIFT> + <F10> abre un
men contextual de funciones y opviones VLISP. Esto
facilita, por ejemplo, copiar y pegar texto en la lnea de
comandos de la consola, buscar texto e iniciar las
utilidades de depuracin VLISP.

La Consola Visual LISP en Entorno Multidocumento (MDI)

AutoCAD 2000 es capaz de abrir varios dibujos a la vez. Esto


se conoce como Interfaz Multidocumento (Multiple Document
Interface - MDI) en contraposicin con la interfaz de
documento nico de versiones anteriores*. Hay una nica
ventana de Consola para todos los dibujos AutoCAD abiertos.
Cuando se utilizan las barras de desplazamiento para revisar
las expresiones y mensajes de la consola, los veremos todos,
aunque se hayan emitido para distintos dibujos. Esta es otra
diferencia en relacin con la ventana de texto de AutoCAD,
que slo es capaz de mostrar los comandosque corresponden
al dibujo activo. Dicho de otra manera, cada dibujo tiene su
propia ventana de texto, pero comparten una sla Consola
VLISP. El cambio de contexto es automtico al cambiar de
dibujo en AutoCAD. El dibujo activo en AutoCAD es siempre el
dibujo activo en VLISP. El nombre del dibujo activo aparece
en la barra de ttulo de la aplicacin.
El men Contextual en la Consola

El pulsar el botn derecho del


ratn sobre cualquier lugar de la
ventana de la Consola abre un
men contextual donde, segn
est o no seleccionado algn
texto, se habilitarn algunas de
las siguientes opciones:

Cut

Borra el texto seleccionado de la Consola y lo transfiere


al Portapapeles de Windows**.
Copy
Copia el texto seleccionado al Portapapeles de
Windows**.
Paste
Pega el contenido del Portapapeles de Windows en la
posicin indicada por el cursor**.
Clear Console window
Vaca la Ventana de la Consola.
Find
Busca el texto especificado en la Consola.
Inspect
Abre el dilogo de la utilidad Inspect.
Add Watch
Abre la ventana de la utilidad Watch.
Apropos
Abre la ventana del Apropos.
Symbol Service
Abre el dilogo de la utilidad Symbol Service.
Undo
Deshace la ltima operacin.
Redo
Anula el efecto del ltimo Deshacer (Undo).
AutoCAD Mode
Transfiere toda las entradas a la lnea de comandos de
AutoCAD para su evaluacin.
Toggle Console Log
Copia la salida de la Consola a un archivo de registro
(log file).
Cmo utilizar la Consola para seguir este Curso:

La consola es la herramienta fundamental que utilizaremos


para seguir este curso. Encontraremos fragmentos de cdigo
como ste (que fue ya citado en la Introduccin):
(defun extents (plist)
(list (apply 'mapcar (cons 'min plist))
(apply 'mapcar (cons 'max plist))))

Podemos seleccionar dicho fragmento en nuestro browser


utilizando el ratn y copiarlo (<CTRL> + <V>), para despus
pegarlo en la consola.

Hecho esto, pulsamos <INTRO> para que se evale el


contenido de la consola, con lo que ya estar definida la
funcin EXTENTS. Esta funcin requiere como argumento una
lista de puntos (entendindose por puntos una lista de tres
nmeros reales representando las coordenadas X, Y, Z.
Supongamos que queremos utilizar la lista:
'((162.75 35.76 145.99)
(127.77 25.37 91.72)(139.355 1.40 0.088)
(242.12 59.34 121.08)(260.897 64.92 30.33)
(299.29 76.33 -55.96)(187.13 -9.28 235.85)
(313.10 -37.47 96.17))
Para ello la introducirmos en la consola (tambin podemos
copiar y pegar) una nueva expresin con el nombre de la
funcin y la lista como nico argumento:

Y entonces, pulsando <INTRO> obtendremos el resultado


devuelto:

Obsrvese cmo los colores identifican los componentes de


las expresiones, rojo para los parntesis, azul para las
funciones, verdeazul para los nmeros reales. Una vez
evaluada los colores del texto cambian a negro, con lo que se
identifica fcilmente qu formas son las que est en
condiciones de ser evaluadas.

* AutoCAD 2000 puede configurarse para trabajar en modo


de documento nico. Para ello se activa la variable de sistema
SDI. El valor por defecto de SDI es 0, cambindolo a 1 se
pasa a trabajar en modo de documento nico. Trabajando en
este modo, la ventana de texto de AutoCAD contendr los
comandos emitidos para los sucesivos dibujos abiertos.
** Es posible realizar operaciones de cortar, copiar y pegar
entre la consola de VLISP y la ventana de texto de AutoCAD.

El Editor Visual LISP

Es ms que un simple editor de texto. Ser, en realidad,


nuestro lugar de trabajo habitual para la programacin LISP
dentro de AutoCAD. Cada fichero de programa abierto tendr
su propia ventana del Editor
Un programa en el editor tendr ms o menos este aspecto:

Codificacin sintctica por color

Lo que primero llama la atencin la ventana del editor es el


color que adoptan los diferentes componentes del programa.
El editor identifica las distintas partes de un programa LISP y
le asigna distintos colores. Esto permite detectar a primera
vista elementos tales como nombres de funcin, nmeros
enteros o reales y cadenas, distinguindolos de los nombres
de funciones y variables asignados por el usuario. Los errores
mecanogrficos saltan as a la vista de manera inmediata.
Estos colores pueden personalizarse a gusto del usuario.
Controles de la Ventana del Editor

La ventana del Editor no posee Barras de Mens ni de


Herramientas. Al estar el foco situado en una ventana del
Editor se activarn las opciones de Men y las Herramientas

de la ventana de la Aplicacin que pueden usarse para


operaciones del Editor. Muchas de las opciones pueden
tambin ser ejecutadas desde el men contextual que se abre
al pusar el botn derecho del ratn. Existe la posibilidad de
utilizar tambin las combinaciones de teclas rpidas usuales
en los editores de texto y adems algunas combinaciones que
se utilizan para funciones exclusivas de este editor. En
trminos generales, adems de la codificacin por color el
editor ofrece otras ayudas que facilitan grandemente el
desarrollo de programas. Algunas de estas utildades son:

Comprobacin del cierre de parntesis


Formateo del Texto
Comentarios automticos en los cierres de Expresiones

Comentado y Descomentado automtico de las lneas


seleccionadas
Bsqueda y Sustitucin de Texto
Comprobacin de la Sintaxis
Carga de expresiones LISP para ser probadas.

En los prximos apartados pasaremos a exponer estas


funcionalidades:

Barras de Herramientas
Men Contextual
Teclas Rpidas
Copias de Seguridad

El Editor VLISP viene configurado para


hacer siempre copias de seguridad de
los ficheros. Estas copias de seguridad
se sitan en el mismo directorio de la
fuente del programa usando el mismo
nombre y la extensin _ls. De esta
manera la copia de seguridad del
fichero caras.lsp se llamar
caras._ls. Para recuperar la ltima
versin guardada de un fichero se
emplea la opcin Revert del men Files.

Barras de Herramientas

Casi todas las funcionalidades del programa pueden


accederse desde iconos de las Barras de Herramientas. Los
iconos que aparecen agrisados cuando se activa la ventana
del Editor no son utilizables en este contexto. Las
Herramientas utilizables para operaciones en el Editor son:
Herramientas de
Edicin
Bsqueda y
Marcadores
Revisin y
Formateo
Acceso a otras
Ventanas de la
Aplicacin
Utilidades de
Depuracin
Herramientas de Edicin

Esta barra incluye las herramientas de edicin acostumbradas en todo


programa Windows, adems de una propia para completar nombres de
smbolos:

Crear nuevo archivo.


Abrir un archivo existente.
Guardar el contenido de la ventana del editor.
Imprimir
Cortar Texto copindolo al Portapapeles. *
Copiar Texto al Portapapeles.*
Pegar Texto desde el Portapapeles.*
Deshacer la ltima operacin.
Rehacer lo deshecho en la operacin anterior.
Completar el nombre de un smbolo.

Completar Nombres de Smbolos

La Barra de Herramientas de Edicin incluye


una herramienta para completar nombres de
Smbolos. Este Icono realiza una bsqueda
inteligente de nombres de smbolos definidos en
el sistema. Al teclear algunas letras del nombre,
el pulsar este icono inicia la bsqueda. Segn la
cantidad de smbolos que pudieran
corresponder a los caracteres tecleados, puede
abrir un men contextual en la posicin del
cursor, abrir la ventana de resultados de
Apropos o abrir la ventana de inicio de
bsqueda de Apropos si fuera demasiado
extensas las opciones posibles (por ejemplo,
teclear una sla letra inicial). A esta funcin
puede accederse desde el Men
Search>Complete Word by Apropos... y
tambin con la combinacin de teclas rpidas
<CTRL> + <SHIFT> + <BARRA
ESPACIADORA>
Herramientas de Bsqueda de Texto

Bsqueda de texto en mltiples ficheros


La bsqueda de una expresin puede realizarse tanto en el fichero
que se edita como en los ficheros del proyecto u otros grupos de
ficheros seleccionados. Desde el Men se accede mediante
Search>Find o mediante las teclas rpidas <CTRL> + <F>.
La caracterstica ms
interesante de la
herramienta de
bsqueda del Editor
VLISP es su capacidad
de buscar en un grupo
de ficheros
seleccionados y mejor
an, en los ficheros que
configuran un proyecto.
El resultado de la
bsqueda se muestra
en una ventana de
salida, llamada <Find
Output>, donde
aparecen completas las
expresiones donde se
emplea el trmino
buscado. Se puede
configurar la
herramienta de
bsqueda para que
inserte marcadores

que encuentre el
trmino buscado, de
manera automtica.
Para ello se deber
marcar la casilla Mark
Instances (Marcar
Buscar y Reemplazar
Instancias)
Permite buscar y reemplazar texto en la ventana activa del Editor. Se
accede a esta opcin desde el men Search>Replace... (Teclas <CTRL>
+ <H>).
Memorizacin de bsquedas anteriores
Los trminos utilizados en bsquedas anteriores se guardan en una lista
desplegable para su reutilizacin.
Insercin de Marcadores
Los marcadores permiten desplazarse dentro del texto de marcador en
marcador. Disponible en el men Search>Bookmarks>Toggle Bookmark.
Hay problemas con los marcadores al usar la opcin de formateo
automtico del texto. (ver nota ms abajo).
Herramientas de Revisin y Formateo

Carga de Expresiones LISP Seleccionadas


A medida que se escriben, las expresiones seleccionadas pueden
cargarse para ser evaluadas. Al ejecutarse la carga el foco pasa a la
ventana de la Consola VLISP. Disponible en el Men como Tools>Load
Selection (<CTRL> + <SHIFT> + <E>)
Carga de la Ventana del Editor
Puede cargarse tambin para su
ejecucin el contenido total
actual de la ventana del Editor y
no slo las expresiones
seleccionadas. En ambos casos
se informar de los errores que
impidan la carga del programa,
aunque no de los errores
sintcticos que pudieran existir.
Desde el men Tools>Load Text
in Editor (<CTRL> + <ALT> +
<E>)
Comprobacin del Cdigo Seleccionado
Comprueba automticamente la correccin del cdigo tecleado. Puede
comprobar todo el contenido de la ventana o slo de las expresiones
seleccionadas. Los resultados de la comprobacin pasan a la ventana
Build Output. En el ejemplo siguiente se ha suprimido intencionalmente
uno de los argumentos necesarios para ls funcin CONS, lo que es
detectado al ejecutar la comprobacin. Esta opcin est disponible
desde el men Tools>Check Selection o con la combinacin de teclas
<CTRL> + <SHIFT> + <C>.

Comprobacin de la Sintaxis del Programa


El Editor posee una herramienta para comprobar la sintaxis del cdigo
tecleado. El resultado pasa a una ventana llamada Build Output,
donde se sealan no slo los errores evidentes sino determinadas
situaciones que deben ser manejadas con cierto cuidado. Aplicada la
comprobacin de Sintaxis al cdigo anterior obtendramos la siguiente
advertencia:

Esto no impide la ejecucin del programa y corresponde a una tcnica


de programacin perfectamente vlida en LISP, donde una funcin
puede siempre ser empleada como dato. Esta opcin se encuentra
tambin en el men Tools>Check Text in Editor
(<CTRL> + <SHIFT> + <C>).
Formateo del Texto
El editor tiene opciones para formateo del texto, haciendo identaciones
de manera automtica. El estilo de formateo puede ser personalizado en
cierta medida. Puede formatearse todo el contenido de la ventana o slo
las lneas seleccionadas.
Nota: Aunque no lo hemos encontrado descrito en la documentacin del
programa, cuando se formatea un texto que contiene marcadores, stos
se trasladan al inicio del bloque seleccionado para su formateo. De
manera que si tenemos varios marcadores establecidos y formateamos
todo el contenido de la ventana del editor, perderemos los marcadores
quedando slo uno en la primera lnea de la ventana del editor, lo que
obviamente quita toda utilidad que pudiera tener esta funcin de
insercin de marcadores.Comentarios automticos de cierre de

Expresin
Entre las opciones de formateo del texto, adems de la identacin se
incluye la posibilidad de incluir comentarios al cierre de los parntesis
que indican a que funcin corresponden cuando dicha funcin abarca
varias lneas.
Comentado y Descomentado automtico de las lneas seleccionadas
Los comentarios se destacan mediante el esquema de colores elegido
con fondo gris, pero adems de ello, la inclusin de los caracteres <;;;>
al inicio de la lnea se realiza mediante una opcin del men Edit>Extra
Commands>Comment Block y se quitan mediante Edit>Extra
Commands>Uncomment Block.
Si se estuvieran editando archivos DCL, los caracteres introducidos como
seal de comentario sern dos barras inclinadas <//>.
Ayuda
Esta barra de Herramientas incluye tambin el Icono para el Acceso a la
Ayuda en-lnea.
Acceso a Otras Ventanas de la Aplicacin

Estas Herramientas permiten Acceder a las ventanas de:

Autocad
Otras Ventanasde Visual LISP, incluyendo las de otros ficheros abiertos
para su edicin.
La Consola Visual LISP
La ventana de Inspeccin de objetos LISP y AutoCAD.
El Trace Stack, que guarda la memoria de pila de errores.
El Symbol Service para la gestin de Smbolos.
La Utilidad de Apropos.
La Utilidad de Watch.

Utilidades de Depuracin

Slo tres de las herramientas se encuentran disponibles cuando est activa la


ventana del Editor:

Insertar Punto de Ruptura.


Aadir el smbolo seleccionado a la ventana de Watch.

Resaltar en el editor el cdigo que provoc la ltima interrupcin en la


ejecucin del programa.

* Es posible realizar operaciones de cortar, copiar y pegar


entre el Editor VLISP y la ventana de texto de AutoCAD.

Men Contextual del Editor

El pulsar el botn derecho del ratn sobre cualquier


lugar de la ventana del Editor abre un men
contextual donde, segn est o no seleccionado
algn texto, se habilitarn algunas de las siguientes
opciones:
Cut
Borra el texto seleccionado de la Consola y lo
transfiere al Portapapeles de Windows*.
Copy
Copia el texto seleccionado al Portapapeles de
Windows*.
Paste
Pega el contenido del Portapapeles de
Windows en la posicin indicada por el
cursor*.
Find
Busca el texto especificado en una o ms
ventanas del Editor.
Go to Last Edited
Desplaza el cursor hacia la ltima posicin
editada.
Toggle Breakpoint
Coloca un punto de ruptura en la posicin del
cursor, o lo elimina en caso de que ya existiera
uno en dicha posicin.
Inspect
Abre el dilogo de la utilidad Inspect.
Add Watch
Abre la ventana de la utilidad Watch.
Apropos
Abre la ventana del Apropos.

Symbol Service
Abre el dilogo de la utilidad Symbol Service.
Undo
Deshace la ltima operacin.
Redo
Anula el efecto del ltimo Deshacer (Undo).

Teclas Rpidas

Las siguientes combinaciones de teclas rpidas son


caractersticas especficas de este editor:
Comandos de ARCHIVO:

<CTRL> + <S>
Guarda el contenido de la ventana activa del Editor.
<CTRL> + <ALT> + <S>
Guarda el contenido de la ventana activa del Editor con
otro nombre de archivo.
<CTRL> + <SHIFT> + <S>
Guarda el contenido de todas las ventanas de Editor
abiertas.
<CTRL> + <F4>
Cierra la ventana de Editor activa.
<CTRL> + <P>
Imprime el contenido de la ventana de Editor activa.
Comandos de Edicin:

<CTRL> + <Z>
Deshacer la ltima operacin en el Editor. Soporta ilimitadas

operaciones de Deshacer, hasta la ltima ocasin en que se


guard el contenido del Editor a disco. Una vez guardado es
imposible deshacer. En ese caso, si fuera necesario, habra que
recuperar la copia de seguridad mediante la opcin
Files>Revert.
<CTRL> + <V>
Pegar el contenido del Portapapeles en el lugar sealado por el
cursor.
<SUPR>
Borrar el Texto sealado o el carcter a la derecha del cursor.
<CTRL> + <A>
Seleccionar todo el contenido de la ventana del Editor.
<CTRL> + <M>
Abre un men desplegable con las opciones de bsqueda del
cierre de parntesis.
<CTRL> + <)>
Desplaza el cursor hasta el parntesis de cierre correspondiente.
<CTRL> + <(>
Desplaza el cursor hasta el parntesis de apertura
correspondiente.
<CTRL> + <SHIFT> + <)>
Selecciona la expresin hasta el parntesis de cierre
corresondiente, resaltndola en vdeo inverso.
<CTRL> + <SHIFT> + <(>
Selecciona la expresin hasta el parntesis de apertura
corresondiente, resaltndola en vdeo inverso.
<CTRL> + <E>
Abre un men desplegable con una serie de comandos
adicionales:

Identar
Bloque de
Texto.
Suprimir la
Identacin
de un
bloque de
Texto.
Identar
hasta el
nivel
actual
Aadir un
prefijo a
cada lnea
de texto
selecciona
da.
Aadir
texto al
final de
cada lnea
selecciona
da.
Marcar el
bloque
selecciona
do como
comentari
o.
Desmarcar
como
comentari
o el bloque
selecciona
do.
Guardar
bloque de
texto
selecciona
do a un
archivo.
Convertir
el texto
selecciona

do a
mayscula
s.
Convertir
el texto
selecciona
do a
minsculas
.
Cambiar a
mayscula
s la
primera
letra de
cada
palabra.
Insertar
Fecha.
Insertar
Hora.
Definir el
formato de
fecha y
hora.

Ordenar
alfabtica
mente las
lneas
selecciona
das.

Insertar el
contenido
de un
archivo de
texto en el
lugar
indicado
por el
cursor

Borrar
desde la
posicin
del cursor

hasta el
final de la
lnea.

Borrar
espacios
en torno a
la posicin
actual del
cursor.

Comandos de Bsqueda:

<CTRL> + <F>
Buscar texto.
<CTRL> + <H>
Buscar y sustituir texto.
<CTRL> + <BARRA ESPACIADORA>
Completar una palabra por similitud a otras existentes
en la ventana actual del Editor. Cuando ya se ha
tecleado un nombre anteriormente, El editor VLISP
facilita el incorporarlo de nuevo al documento con slo
teclear los caracteres iniciales. Si en el ejemplo de arriba
quisiramos teclear de nuevo el nombre de la funcin
PosVert bastara teclear Po y despus pulsar <CTRL> +
<BARRA ESPACIADORA>. Si en lugar de encontrar
PosVert encontrara el nombre de variable pos, bastara
con volver a pulsar <CTRL> + <BARRA ESPACIADORA>
cuantas veces fuera necesaro para llegar al texto
deseado.
<CTRL> + <SHIFT> + <BARRA ESPACIADORA>
Completar una palabra mediante APROPOS (buscando
en todo el conjunto de smbolos AutoLISP.
<ALT> + <.>
Poner o quitar marcador.
<CTRL> + <.>
Desplazarse al prximo marcador.
<CTRL> + <,>
Desplazarse al marcador anterior.
<CTRL> + <SHIFT> + <.>
Seleccionar hasta el prximo marcador.

<CTRL> + <SHIFT> + <,>


Seleccionar hasta el marcador anterior.
Comandos de Vistas:

<CTRL> + <SHIFT> + <I>


Abre una ventana de Inspeccin para introducir una
expresin.
<CTRL> + <SHIFT> + <T>
Abre la ventana de Inspeccin de Trace.
<CTRL> + <SHIFT> + <R>
Abre la ventana de Inspeccin para la ltima pila de
error.
<CTRL> + <SHIFT> + <S>
Abre una ventana de Inspeccin para un smbolo.
<CTRL> + <SHIFT> + <W>
Abre la ventana de Vigilancia (WATCH).
<CTRL> + <SHIFT> + <A>
Abre la ventana APROPOS para ayuda con expresiones
LISP.
<CTRL> + <SHIFT> + <B>
Muestra los puntos de interrupcin actuales (en todos
los programas abiertos, no slo la ventana activa).
<F6>
Abre la Consola Visual LISP y/o la pone en primer plano.
Comandos del Proyecto:

<CTRL> + <SHIFT> + <P>


Abre un proyecto existente.
Comandos de Depuracin:

<CTRL> + <W>
Aadir una expresin a la ventana de Vigilancia
(WATCH).
<F9>
Aade o suprime un punto de interrupcin en la posicin
actual del cursor.
<CTRL> + <SHIFT> + <F9>
Suprime todos los puntos de interrupcin.

<CTRL> + <F9>
Busca y resalta el cdigo que dio origen a la ltima
interrupcin.
Herramientas de Desarrollo:

<CTRL> + <SHIFT> + <E>


Carga y evala el cdigo seleccionado.
<CTRL> + <ALT> + <E>
Carga y evala el cdigo contenido en la ventana activa
del Editor.
<CTRL> + <SHIFT> + <C>
Comprueba la sintaxis de las expresiones seleccionadas.
<CTRL> + <ALT> + <C>
Comprueba la sintaxis del cdigo contenido en la
ventana activa del Editor.
<CTRL> + <SHIFT> + <F>
Formatea las expresiones seleccionadas.
<CTRL> + <ALT> + <F>
Formatea el cdigo contenido en la ventana activa del
Editor.
Controles de Ventanas:

<ALT> + <F6>
Ajusta la ventana activa al espacio disponible en
pantalla.
Comprobacin del cierre de parntesis
Las combinaciones de teclas <CTRL> + <(> y <CTRL>
+ <)> permiten localizar el parntesis de apertura o el
parntesis de cierre respectivamente que corresponda a
partir de la posicin donde se sita el cursor. Si se pulsa
simultneamente <SHIFT> el texto quedar
seleccionado (en vdeo inverso).
Completar Texto
Cuando ya se ha tecleado un nombre anteriormente, El
editor VLISP facilita el incorporarlo de nuevo al
documento con slo teclear los caracteres iniciales. Si en
el ejemplo de arriba quisiramos teclear de nuevo el
nombre de la funcin PosVert bastara teclear Po y

despus pulsar <CTRL> + <BARRA ESPACIADORA>. Si


en lugar de encontrar PosVert encontrara el nombre de
variable pos, bastara con volver a pulsar <CTRL> +
<BARRA ESPACIADORA> cuantas veces fuera necesaro
para llegar al texto deseado.

TIPOS DE DATOS

Antes de iniciarnos en la programacin LISP, examinaremos


los datos con que este lenguaje opera. Las posibilidades de un
lenguaje de programacin estn directamente relacionadas
con la oferta de procedimientos y funciones y en sobre qu
tipos de datos pueden ellos operar.
Los tipos de datos originales son los TOMOS y las LISTAS.
Los TOMOS y las LISTAS son mutuamente excluyentes: un
objeto LISP es lo uno o lo otro. Con una excepcin: la lista
vaca o NIL, que estudiaremos ms adelante. Las listas se
construyen recursivamente a partir de tomos y/o listas.
Ejemplos:
TOMOS

LISTAS

a
juan
45

()
(juan)
(a juan 45 z5mn)
((juan 45) a
((z5mn)))

z5mn

AutoLISP y Visual LISP utilizan adems otros tipos de datos


que estudiaremos ms adelante y que resultan necesarios
para la gestin de los dibujos en el entorno AutoCAD.
Tanto los tomos como las listas son expresiones vlidas LISP
que el intrprete lee y evala. Las reglas para la evaluacin
de ambos tipos de objetos se describen a continuacin:
TOMOS

Los tomos son las expresiones LISP ms elementales.


Siempre tienen un nombre constituido por una secuencia
de caracteres y por ello se asemejan a las palabras de
un lenguaje. Los nombres de tomos se separan de
otras expresiones mediante espacios en blanco,
parntesis o cambios de lnea. Un tomo no es divisible.
Como norma general, todos los elementos que no sean
una lista se consideran tomos. Al recibir un tomo, el
evaluador lisp intenta determinar su valor. Este valor
puede estar representado por el nombre mismo del
tomo, que entonces consideraremos como una
"constante" o puede ser un objeto LISP distinto, en
cuyo caso estaremos ante un tomo "simblico". Los
tomos simblicos se utilizan dentro de los programas
para almacenar valores, siendo conocidos entonces
como "variables".
LISTAS:
El nombre LISP viene de LISt Processing (Procesamiento
de Listas), indicando el mecanismo fundamental sobre el
que se desarrolla el lenguaje. Las listas LISP son grupos
de valores relacionados, separados por espacios e
incluidos entre parntesis redondos "(" y ")". En LISP, el
orden de los elementos incluidos en una lista es
significativo. En esto se distingue el concepto de lista del
concepto de conjunto, en el que el ordenamiento de los
trminos no tiene relevancia. Otra diferencia entre listas
y conjuntos reside en que en una lista pueden haber
trminos repetidos, mientras que en un conjunto cada
trmino ocurre una sla vez. Las listas proporcionan un
mtodo eficaz para almacenar valores relacionados.
AutoCAD expresa los puntos 3D como una lista de tres
nmeros reales donde el primer valor es el de la
coordenada X, el segundo la coordenada Y, el tercero la
coordenada Z. Esto indica que el orden de los trminos
de una lista es significativo y en esto se diferencia del
concepto de conjunto. Adems una lista admite trminos
repetidos. Dentro de las posibles listas podemos
distinguir tres casos:

Listas de un nivel
Listas anidadas
La lista vaca

TIPOS DE DATOS ESPECFICOS DE AUTOCAD:

CONJUNTOS DE SELECCIN
Los conjuntos de seleccin son grupos compuestos por
uno o varios objetos (entidades). Las rutinas de
AutoLISP permiten aadir o suprimir de forma
interactiva objetos de los conjuntos de seleccin.
NOMBRES DE ENTIDAD
Un nombre de entidad es un identificador numrico
asignado a los objetos de un dibujo. En realidad, se trata
de un puntero a un archivo mantenido por AutoCAD, en
el que AutoLISP puede encontrar el registro de la base
de datos de objetos. Este puntero suele cambiar de una
sesin de trabajo a otra.
DESCRIPTORES DE ARCHIVO
Los descriptores de archivo son identificadores
alfanumricos asignados a archivos abiertos por Visual
LISP. Cuando sea necesario que una funcin de Visual
LISP lea o escriba en un archivo, debe hacerse
referencia a su identificador.
SUBRUTINAS, SUBRUTINAS EXTERNAS Y
FUNCIONES DE USUARIO
Funciones Nativas LISP o funciones externas cargadas
desde archivos compilados FAS VLX y archivos fuente
LISP.
TABLAS DE PAGINACIN
OBJETOS Y TIPOS DE DATOS ACTIVEX
Objetos propios y determinados formatos para los datos
que se pasan a los mtodos ActiveX.

COMPROBACIN DEL TIPO DE DATO:

FUNCIN TYPE
Devuelve el tipo de un elemento designado
(type elemento)

TOMOS

TOMOS SIMBLICOS (S-ATOMS):


Un tomo simblico es un tomo que representa algo
ms, como el nombre de una funcin o el valor de una
variable. Un tomo simblico si no tiene asignado un
valor, al evaluarse devolver una lista vaca. Las
funciones como set, setq y defun permiten asignarle
valores a los tomos-S.
Los nombres de smbolos no distinguen entre
maysculas y minsculas, y pueden ser cualquier
secuencia de caracteres de notacin y alfanumricos a
excepcin de los siguientes: ( ) . ' " ; .
Un nombre de smbolo no puede estar compuesto slo
por caracteres numricos ya que un nmero se
representa a s mismo y es por tanto una constante. Lo
mismo sucede con los nombres entrecomillados.

VARIABLES:
Cuando un smbolo se utiliza para almacenar
temporalmente datos necesarios para la ejecucin del
programa suele identificarse como una variable. La
funcin (atoms-family 0) nos devuelve todos los
tomos-S evaluados como no-nil en un momento
determinado.
VARIABLES GLOBALES Y LOCALES:
La funcin SETQ es el medio fundamental para asociar
los smbolos a valores:
(SETQ <smbolo> <valor>)
Esto es equivalente a:
(SET (QUOTE <smbolo>) <valor>)

Es decir, que toma el nombre de smbolo sin evaluar, y le


asigna el valor deseado. En este sentido se dice que
SETQ es una "Forma Especial". Una variable creada con
SETQ es una variable global. Esto quiere decir que
retiene su valor fuera del programa que la utiliza. Una
variable de este tipo afectara a cualquier otro programa
que utilizara el mismo smbolo.
Las variables locales son aquellas que retienen su valor
slo mientras la funcin que las define est activa. Las
variables locales se eliminan tan pronto termina la
operacin de la funcin donde se definieron, se
desechan automticamente y el sistema recupera el
espacio de memoria que las variables ocupaban. Esto se
conoce como "recoleccin de desechos" (garbage
collection) automtica. Las variables locales resultan por
ello ms eficientes en el uso de la memoria. Visual LISP
no tiene una funcin especial para la creacin de
variables locales. Las mismas deben declararse
expresamente en la lista de parmetros de la funcin
DEFUN.
Para ms informacin consultar a R. Urban, Using Local
Variables?
CONSTANTES:
Los nmeros y las cadenas son formas auto-evaluativas.
Estos datos se distinguen de los tomos simblicos en
que no pueden representar otra cosa que el su propio
valor, es decir que se representan a s mismos. Entre los
valores constantes tenemos los nmeros y las cadenas.
NMEROS
Los valores numricos que emplea Visual LISP pueden
ser enteros o reales.
CADENAS DE TEXTO
Una cadena se representa mediante una sucesin de
caracteres (letras, nmeros y signos de puntuacin)
encerrados entre comillas dobles. Estas comillas dobles
de apertura y cierre no forman parte de la cadena de
caracteres en s misma, sino que constituyen la manera
de indicar al evaluador LISP que se trata de este tipo de
dato. Si se quiere tener comillas dobles como parte de la
cadena, deber precederse el carcter comillas por una
contrabarra: "Esto es una \"Palabra\"

entrecomillada". La contrabarra es un carcter de


control que permite incluir cambios de lnea,
tabuladores, y otros caracteres especiales en una
cadena. Para incluir una contrabarra como parte de la
cadena deben escribirse dos contrabarras, la primera
como carcter de control y la segunda para graficar la
contrabarra: "Cadena incluyendo \\". Las cadenas
individuales tienen una limitacin de 132 caracteres. En
versiones anteriores de AutoCAD, los nombres de tablas
de smbolos se convertan automticamente a
maysculas. En AutoCAD 2000 se conserva el tipo de
carcter utilizado, sean maysculas o minsculas. Al
hacer comprobaciones de igualdad de cadenas puede ser
necesario por ello realizar conversiones a un mismo tipo
de letra utilizando la funcin STRCASE.

NMEROS ENTEROS Y REALES

ENTEROS
Son nmeros sin coma decimal. Los enteros de AutoLISP son
nmeros de 32 bits con signo cuyos valores estn
comprendidos entre +2.147.483.648 y -2.147.483.647.
Aunque AutoLISP utiliza internamente valores de 32 bits, los
que se transmiten de AutoLISP a AutoCAD y viceversa estn
limitados a 16 bits. Por tanto, no pueden transmitirse a
AutoCAD valores superiores a +32767 ni inferiores a -32768.
Sin embargo, VLISP acepta valores fixnum entre los valores
lmite de:

MAX-SHORTINT = 32767
MOST-POSITIVE-FIXNUM = 2147483647
MOST-NEGATIVE-FIXNUM = -2147483647

Un nmero mayor o menor se convierte automticamente en


real.
REALES

Contienen coma decimal. Los comprendidos entre -1 y 1


deben empezar por cero. Los nmeros reales se almacenan
en formato de coma flotante de doble precisin, lo cual
proporciona una precisin mnima de 14 dgitos significativos,
aunque el rea de comandos de AutoCAD muestra slo 6.
Los valores lmites son:
MOST-POSITIVE-DOUBLE-FLOAT =
1.797693134862315e+308
MOST-NEGATIVE-DOUBLE-FLOAT=
-1.797693134862315e+308
Un nmero mayor, devuelve infinito:
_$ 1.797693134862316e+308
1.#INF
_$ (setq val 1.797693134862316e+308)
1.#INF
_$ (type val)
REAL
_$ (setq *INFINITO* 2.797693134862316e+308)
1.#INF
_$ (eq *INFINITO* val)
T
_$ (/ 125678 *INFINITO*)
0.0
Se puede establecer una variable global *INFINITO* con:
(setq *INFINITO* 1.797693134862316e+308) y utilizarlo
como tal en operaciones trigonomtricas.
Pueden expresarse en notacin cientfica, que consta de una
e o E opcional seguida por el exponente del nmero (por
ejemplo, 0.0000041 es lo mismo que 4.1e-6). El smbolo pi
se evala como la constante real 3,1415...
FUNCIONES DE CONVERSIN ENTRE ENTEROS Y REALES:

(fix nmero)
Devuelve la conversin de un nmero real en el prximo
entero menor.
(float nmero)
Devuelve la conversin de un nmero entero en un
nmero real.

CONSIDERACIONES SOBRE LA CONVERSIN ENTRE NMEROS REALES Y


ENTEROS

La funcin fix en realidad lo que ejecuta es un truncamiento


del nmero real hacia cero. Es decir, devuelve el nmero
entero ms prximo a cero. As (fix 4.7) devolver 4, es
decir, el nmero entero menor ms cercano al suministrado
como argumento. Pero (fix -4.7) devolver -4, que es el
entero mayor ms cercano. En las definiciones de Common
LISP, fix equivaldra a la funcin truncate.
Steele menciona en CLTL2 otras posibilidades de conversin
entre reales y enteros:
floor
convierte su argumento mediante un truncamiento hacia
infinito negativo; es decir, que el resultado es el entero
mayor que no es mayor que el argumento.
ceiling
convierte su argumento mediante un truncamiento hacia
infinito positivo; es decir, que el resultado es el entero
menor que no es menor que el argumento.
truncate
convierte su argumento mediante un trucamiento hacia
cero; es decir, que el resultado es el entero del mismo
signo que el argumento y que posee la mayor magnitud
entera que no es mayor que el argumento.
round
convierte su argumento mediante el redondeo al entero
ms cercano; si el nmero se encuentra exactamente a
mitad de camino entre dos enteros (es decir, en la forma
entero + 0.5), entonces se redondea al entero par ms
prximo (divisible por 2).
Ms adelante desarrollaremos funciones para implementar
algunos de estos conceptos que no aparecen como primitivas
de Visual LISP.*
*Ver el captulo REALES A ENTEROS: TRUCAMIENTO O
REDONDEO.

LISTAS Y CONSES

Por la importancia dentro de LISP del tipo de datos LISTA,


citamos in extenso el apartado 2.4 de CLTL2,
Un CONS es una estructura de informacin que contiene dos
componentes llamados el CAR y el CDR. La utilizacin
fundamental de los CONSES es como representacin de
LISTAS.
Una LISTA se define recursivamente ya sea como la lista vaca

o como un CONS cuyo componente CDR es una lista. Una lista


es, por consiguiente, una cadena de CONSES enlazados por
sus componentes CDR y terminada por un NIL, la lista vaca.
Los componentes CAR de los conses son conocidos como los
elementos de la lista. Para cada elemento de la lista hay un
CONS. La lista vaca no tiene ningn elemento.
Para comprender mejor lo anterior, adelantaremos la mencin
de la funcin bsica de construccin de listas, que es la
funcin CONS (que se explica en el apartado FUNCIONES DE
CONSTRUCCIN DE LISTAS). Expresado en trminos de
esta funcin, la anterior definicin de una lista como una
cadena de CONSES sera:

Una LISTA se expresa mediante la escritura de los elementos


de la lista ordenados, separados por espacios en blanco
(caracteres de espacio, tabulador o retorno) y rodeados por
parntesis. Por ejemplo:
(a b c)
;Una lista de tres smbolos
(2.0 (a 1) "*")
;Una lista de tres cosas
diferentes: un nmero real
;otra lista y un carcter
asterisco

Nota: El cdigo del ejemplo anterior ha sido


modificado para adaptarlo a las convenciones de
AutoLISP/Visual LISP
La lista vaca puede por lo tanto ser expresada como (), ya
que se trata de una lista sin elementos.
Una lista punteada (dotted list) es una cuyo ltimo cons no
tiene NIL como su CDR, sino otro objeto de informacin (que
tampoco ser un CONS, ya que entonces el CONS
anteriormente mencionado no hubiera sido el ltimo CONS de
la lista).

Tal tipo de lista se conoce como "punteada" debido a la


notacin especial que se emplea en ella: los elementos de la
lista se escriben, al igual que antes, entre parntesis, pero ...
antes del parntesis derecho se escriben un punto (rodeado
por espacios en blanco) y entonces el CDR del ltimo CONS.
Como caso especial, un CONS aislado se expresa escribiendo
el CAR y el CDR entre parntesis y separados por un punto
rodeado de espacios (par punteado). Por ejemplo:
(a . 4)

;Un cons cuyo car es el smbolo a


;y cuyo cdr es un entero
(a b c . d) ;Una lista punteada con tres elementos
cuyo cons final
;tiene el smbolo d en su cdr
Con frecuencia se utiliza el trmino lista para hacer referencia
tanto a verdaderas listas como a listas punteadas. Cuando
resulta importante la distincin, se utilizar el trmino
"verdadera lista" para referirnos a una lista terminada por
NIL. La mayora de las funciones que se dice operan sobre
listas esperan recibir verdaderas listas como argumento.
Por ejemplo, si en el ejemplo de concatenacin de CONSES anterior
el elemento de la derecha del ltimo CONS no hubiera sido NIL (lo
que hubiera incluido un par punteado en la lista), el pasar esta lista

como argumento a una funcin de tratamiento de listas hubiera


producido en determinados casos un error:

A veces se utiliza el trmino rbol para referirse a algunos


CONS y todos los dems CONSES accesibles a l de manera
transitiva a travs de enlaces de CAR y CDR hasta alcanzar
objetos NO-CONS; stos NO-CONSES son conocidos como las
hojas del rbol.

Representacin de LISTAS como rboles.


Tomado de: Corts y Sierra, LISP. Editorial Marcombo,
Barcelona. 1987.
Las listas, las listas punteadas y los rboles no son tipos de
datos mutuamente excluyentes; no son ms que puntos de
vista tiles en torno a las estructuras de CONSES. Hay an
otros trminos tales como LISTA DE ASOCIACIN. Ninguno
de stos son verdaderos tipos de datos LISP.
Los CONSES constituyen un tipo de dato, y NIL es el nico
objeto de tipo NULL. El tipo de dato LISTA significa en LISP la
unin de los tipos de datos CONS y NULL, y por ello engloba
tanto las listas verdaderas como las listas punteadas.
FORMATOS DE LISTAS:

Adems de lo apuntado ms arriba, es conveniente distinguir


entre los siguientes tres formatos de listas:

LISTAS DE UN NIVEL
Contienen slo tomos.

LISTAS ANIDADAS
Contienen a su vez otras listas que se dicen anidadas.
Estas listas anidadas suelen ser conocidas como sublistas. El nmero de niveles de anidacin no est
restringido ni en su profundidad ni en su complejidad. El
nivel ms externo lo llamamos nivel superior o primer
nivel. A los elementos que conforman este nivel los
llamamos elementos de primer nivel.
LISTAS DE ASOCIACIN (A-LIST)
Son listas anidadas que se utilizan con frecuencia como
estructura de datos en LISP. Una A-LIST es una lista de
pares (CONSES) en que cada par constituye una
asociacin. El CAR de uno de estos pares se conoce
como la CLAVE y el CDR constituye el DATO. Una ventaja
de la representacin como A-LIST es la posibilidad de
incrementarla aadindole nuevas entradas al principio
de la lista. Ms an, como la funcin de bsqueda
ASSOC recorre la A-LIST de manera ordenada, las
nuevas entradas pueden "enmascarar" las ms antiguas
de manera que la informacin puede ser modificada de
forma no destructiva.
LA LISTA VACA (NIL)
Como se dijo antes, es la que no contiene ningn
elemento. Se indica como () y recibe un nombre
particular, el de NIL.
La lista vaca tiene un status peculiar en LISP. Es a la
vez un tomo y una lista. Como smbolo representa el
valor lgico de FALSO:

_$ ()
nil
_$ (atom nil)
T
_$ (listp nil)
T
CIERTO Y FALSO
Su negacin (not nil) sera el smbolo T que representa
la condicin lgica de CIERTO.
El smbolo T es tambin una constante en el sentido de
que slo se representa a s mismo.
En Visual LISP, nil y T as como otros elementos que
incluyen los operadores aritmticos (+, -. etc.) son
smbolos protegidos. Cualquier intento de asignarle otro

valor producir un mensaje de advertencia:

Este mensaje aparece como la opcin por defecto y pide


si se desea entrar en un bucle de interrupcin (break
loop). Si se escoge No, el valor del smbolo es
modificado. Si se selecciona S, se interrumpe el
procesamiento y se entra en un ciclo de interrupcin de
Visual LISP, lo que se conoce por el aspecto del smbolo
del evaluador, por ejemplo: _1_$.

El control se ha trasladado a la consola de Visual LISP.


Para asignar valor al smbolo y continuar el
procesamiento se deber pular el botn Continuar en
la barra de herramientas de Visual LISP. Para abortar el
procesamiento se pulsar Reset .
VALORES DEVUELTOS POR LA FUNCIN TYPE

(type dato)
La funcin TYPE permite examinar el tipo a que corresponde
un dato determinado. Los datos que evalan como NIL (por
ejemplo tomos simblicos no vinculados a un valor)
devuelven nil.

El valor devuelto para cada tipo de dato ser alguno de los


tomos que se describen a continuacin:
Tipos LISP:

INT
Nmeros Enteros
REAL
Nmeros de Coma Decimal Flotante
LIST
Listas
STR
Cadenas
SYM
Smbolos
Tipos AutoCAD:

ENAME
Nombres de entidades
FILE
Descriptores de archivo
PAGETB
Tablas de Paginacin de Funciones
PICKSET
Conjuntos de seleccin

SUBR
Funciones AutoLISP internas o funciones cargadas desde
archivos (FAS o VLX) compilados.
USUBR
Funciones de usuario cargadas desde ficheros fuente
LSP.
EXRXSUBR
Aplicaciones ObjectARX Externas.
Tipos ActiveX:

SAFEARRAY
Matriz del tipo Safearray. Las matrices que se pasan a
los mtodos ActiveX deben ser del tipo safearray. Estas
matrices son seguras (safe) porque no es posible el
asignar de manera accidental valores fuera de los lmites
de la matriz provocando una excepcin de datos.
VARIANT
Datos del tipo Variant. Los Variant son en esencia
estructuras que se auto-definen y que pueden contener
diferentes tipos de datos. Por ejemplo, cadenas, enteros
y matrices pueden ser representados por Variants. Junto
a los datos se guarda la informacin que identifica el tipo
de dato. Esta caracterstica de auto-definicin hace de
los Variant tiles medios para pasar parmetros a los
servidores ActiveX.
VLA-object
Objetos ActiveX

FUNCIONES

Una vez conocidos los tipos de datos pasaremos a estudiar


cmo utilizarlos. LISP es un lenguaje de programacin
funcional, es decir que suministra funciones para la
manipulacin de los datos.

Los programas LISP se estructuran como formas y funciones.


Segn Corts y Sierra*,
una FORMA es "una expresin simblica en posicin de ser
evaluada. El cmputo de valores, en LISP, se realiza
simplemente mediante la evaluacin de una FORMA. Todas las
FORMAS tienen valor, sean estas constantes numricas,
tomos literales o expresiones simblicas. Uno de los errores
ms tpicos al programar en LISP es el de tratar de evaluar
una FORMA que no tiene valor. El valor de una FORMA es el
resultado de evaluarla...
Hay que remarcar que los trminos expresin simblica y
FORMA pueden aplicarse a la misma entidad; su aplicacin
depender del contexto. Una LISTA puede considerarse como
un dato, como una expresin simblica o considerarse como
parte de un procedimiento; la misma LISTA puede ser
considerada como una FORMA" .
Las formas se evalan (en relacin con determinado contexto)
para producir valores y efectos colaterales. Las funciones se
invocan aplicndolas a argumentos. (Guy L. Steele Jr.,
Common Lisp the Language, captulo 5). En el entorno
Visual LISP se identifican como FORMAS las funciones de
usuario definidas dentro de un fichero fuente LSP. Al cargar
un programa se recibe la confirmacin de la carga exitosa del
mismo mediante el siguiente mensaje:

Las funciones son conocidas en matemticas. Mediante ellas


se describe algn tipo de relacin entre un grupo de valores.
La adicin y la multiplicacin son funciones simples. Una
funcin ms compleja sera: f(x)=3x2+2x-15
Esta ltima funcin tambin describe una regla de clculo o
algoritmo. Las funciones realizan los clculos (en trminos
LISP, evaluacin) utilizando para ello sus argumentos y
devuelven un resultado. A iguales argumentos
correspondern iguales resultados.
Segn Corts y Sierra**:

En LISP, los programas se construyen a partir de la


composicin de funciones. Esto permite que tales programas
expresen sus propsitos ms claramente que los programas
convencioneles, y que resulten ms fciles de entender y de
mantener, adems de ser ms fciles de construir.
AutoCAD identifica sus funciones LISP primitivas como el tipo
de dato SUBR, mientras que las formas definidas a partir de
ellas pertenecen al tipo de dato USUBR o "sub-rutina de
usuario" La funcin typedevuelve los tipos correspondientes.
La llamada a una funcin toma la forma de una lista cuyo
primer elemento es un tomo simblico que representa a la
funcin llamada. El resto de los elementos de esa lista pueden
ser tomos y otras listas. Estas sublistas se consideran
tambin llamadas a funciones y se evalan para que su valor
resultante pueda ser pasado como argumento a la funcin
que las contiene.
FUNCIONES PRIMITIVAS

Describimos una serie de funciones como primitivas en el


sentido de que estn definidas en la norma del lenguaje, para
distinguirlas de las funciones creadas por el usuario a partir
de aqullas. En LISP se llama a una funcin mediante la
siguiente sintaxis:
(NOMBREFUNCION <Argumento_1> ... <Argumento_n>)
La suma de dos nmeros sera (+ 5 1)
Para evaluarla LISP procede de la siguiente manera:
a. Lee la expresin completa (+ 5 1)
b. La interpreta como una llamada a una funcin y la
identifica como SUMAR <+>
c. Interpreta 5 como primer argumento y 1 como segundo. El
parntesis de cierre le indica que no hay ms argumentos.
d. La funcin <+> se evala para 5 y 1, devolviendo 6 como
resultado, que a falta de otro destino es impreso en pantalla.
Programar LISP significa llamar a funciones. Bsicamente esto
se hace usando el tipo de dato LISTA. Cualquier lista que no
tenga otra interpretacin como forma especial se
considerar una llamada a una funcin, donde el primer
trmino se tomar como el nombre de la funcin y el resto
como sus argumentos. Las listas de llamadas a funcin
pueden estar anidadas, es decir, que una llamada a funcin se

puede estar utilizando como argumento en otra lista que


corresponda a una llamada a otra funcin. El resultado de la
evaluacin de cada nivel de anidacin es devuelto al nivel de
superior, hasta llegar al nivel ms alto, cuyo valor devuelto se
imprimira en la pantalla de texto o la lnea de comandos.
ARGUMENTOS FUNCIONALES

De lo expuesto ms arriba se concluye que en LISP una


funcin es adems un objeto de datos que puede ser
suministrado a otra funcin como argumento. Esta posibilidad
contribuye a la facilidad con que LISP se puede adaptar a las
necesidades de cualquier programa mediante la incorporacin
de nuevas funciones que en su comportamiento resultan
idnticas a las primitivas.
Un programa que admite funciones como datos debe tambin
suministrar alguna manera de invocarlas. Esto se logra en
Visual LISP mediante la funcin APPLY.
APPLY

(apply funcin lista-args)


APPLY, como su nombre en ingls indica, aplica una funcin
(que recibe como primer argumento) a una lista de
argumentos. La funcin puede ser un objeto de cdigo
compilado, una expresin-lambda, o un smbolo. En este
ltimo caso se utiliza el valor funcional global de dicho
smbolo, aunque ste no puede ser una forma especial.
_$ (apply '+ '(2 4 6))
12
_$ (apply '(lambda (x y z)(+ x y z)) '(2 4 6))
12
_$ (apply 'quote '(2 4 6))
; error: bad QUOTE syntax: ((QUOTE 2) (QUOTE 4)
(QUOTE 6))
_1$
; reset after error
Obsrvese el error provocado por utilizar la forma especial
QUOTE.

Otras muchas funciones LISP requieren argumentos


funcionales. Entre las de uso ms frecuente estn las
funciones de mapeado. MAPCAR, por ejemplo toma dos o ms
argumentos: una funcin y una o ms listas (tantas como
parmetros requiera la funcin) y aplica la funcin
sucesivamente a los elementos de cada lista, devolviendo una
lista con los resultados.
_$ (mapcar '+ '(1 2 3) '(10 100 1000))
(11 102 1003)
Otras muchas funciones admiten funciones como argumentos.
Entre las ms utilizadas tenemos VL-SORT y VL-REMOVE-IF.
La primera es una funcin de ordenacin de uso general.
Requiere una lista y un predicado, y devuelve una lista
ordenada pasando sus elementos dos a dos al predicado.
_$ (vl-sort '(3 2 1 3) '<)
(1 2 3)
VL-REMOVE-IF acepta una funcin y una lista, y devuelve
todos los elementos de la lista para los cuales la funcin
devuelva NIL (falso).
_$ (vl-remove-if 'numberp '("a" 3 4 "c" 5 "d" "e"))
("a" "c" "d" "e")
El programar nuevas funciones utilitarias que aceptan
argumentos funcionales es una parte importante del estilo de
programacin funcional que caracteriza a LISP.
FUNCIONES ARITMTICAS BSICAS

Las funciones aritmticas que tienen como argumento un


nmero devuelven distintos valores dependiendo de que el
argumento proporcionado sea un nmero entero o real. Si
todos los argumentos son enteros, el valor devuelto ser
entero. Por el contrario, si alguno o todos los argumentos son
reales, el valor devuelto ser un nmero real. Por ejemplo:
(/ 12 5) devuelve 2, mientras que (/ 12.0 5) devuelve
2.4
Los argumentos de una funcin aritmtica no son
necesariamente nmeros. Cualquier otra funcin que
devuelva un nmero como resultado es admisible como

argumento de una funcin aritmtica. Ejemplo (* (+ 1 5)(20 10))


FUNCIONES BSICAS DE TRATAMIENTO DE CADENAS

Para el tratamiento de cadenas tenemos funciones que


permiten unificar cadenas diferentes, extraer subcadenas de
una cadena mayor, determinar cuntos caracteres hay en una
cadena y transformar los caracteres a maysculas o
minsculas. El predicado WCMATCH permite determinar la
semejanza de cadenas utiliando comodines.
FUNCIONES BSICAS DE ACCESO A LISTAS

Una lista es una manera de representar un conjunto de


tomos y de otras listas. Una lista tiene la forma de un
parntesis de apertura "(" seguido de una serie de tomos o
listas, seguido por otro parntesis de cierre ")". De manera
que cualquier cosa encerrada entre parntesis ser
considerada una lista. Una lista pasada al evaluador LISP ser
tratada como una expresin simblica (S-expresin), es decir,
una llamada a funcin y se considerar el primer trmino de
la lista como el nombre de la funcin. Para que una lista sea
tratada como dato y no como una expresin simblica debe
estar contenida en la forma especial QUOTE. Las funciones
bsicas cuya comprensin es imprescindible para el acceso a
la informacin contenida en listas se pueden reducir a cuatro:
QUOTE, CAR, CDR, y NTH.
FUNCIONES DE CONSTRUCCIN DE LISTAS

Con las funciones del epgrafe anterior podemos descomponer


listas, accediendo a suscomponentes a distintos niveles de
anidacin. Existen otras funciones que podemos utilizar
para componer nuevas listas a base de elementos
individuales, ya sean tomos u otras listas. CONS, LIST y
APPEND son funciones que construyen listas por distintos
procedimientos y con resultados diversos, por lo que es
necesario distinguirlas bien.
FUNCIONES ARITMTICAS BSICAS

Cada una de las funciones incluidas en este apartado requiere


que sus argumentos sean todos nmeros. El pasarle un
argumnto no numrico provocar un error. Operan tanto
sobre nmeros enteros como sobre nmeros reales,
realizando los ajustes pertinentes cuando dichos argumentos
fueran de diferente tipo.
+ (suma)
(+ [nmero nmero] ...)
Si proporciona slo un argumento nmero, esta funcin
devuelve el resultado de sumarlo a cero. Ningn
argumento, devuelve 0.
_$ (+ 1 2 3)
6
_$ (+ 1.0 2 3)
6.0
- (resta)
(- [nmero nmero] ...)
Si utiliza ms de dos argumentos nmero, esta funcin
devuelve el resultado de restar del primer nmero la
suma de todos los nmeros, desde el segundo hasta el
ltimo. Si slo utiliza un argumento nmero, la funcin
devuelve el valor resultante de restar nmero a cero.
Ningn argumento, devuelve 0.
_$ (- 10 1 2 3)
4
_$ (- 10 1 2.0 3)
4.0
* (multiplicacin)
(* [nmero nmero] ...)
Si proporciona slo un argumento nmero, esta funcin
devuelve el resultado de multiplicarlo por uno. Ningn
argumento, devuelve 0.
_$ (* 1 2 3)
6
_$ (* 1 2 3.0)
6.0
/ (divisin)
(/ [nmero nmero] ...)
Si utiliza ms de dos argumentos nmero, esta funcin
divide el primer nmero por el producto de todos los

nmeros del segundo al ltimo y devuelve el cociente


final. Si proporciona slo un argumento nmero, esta
funcin devuelve el resultado de dividirlo por uno.
Ningn argumento, devuelve 0.
_$ (/ 30 2 4)
3
_$ (/ 30 2.0 4)
3.75
1+ (incremento)
(1+ nmero)
Devuelve el argumento aumentado (incrementado) en 1
_$ (1+ 6)
7
1- (decremento)
(1- nmero)
Devuelve el argumento reducido (decrementado) en 1
_$ (1- 6)
5
FUNCIONES DE ACCESO A LISTAS

Existen tres funciones bsicas para acceder a los trminos de


una lista: CAR, QUOTE y CDR.
Funciones CAR y QUOTE:

CAR
CAR admite un nico argumento que debe ser una lista o
una expresin cuyo valor sea una lista y devuelve el
primer elemento de dicha lista. Como LISP siempre
interpreta una lista como una llamada a una funcin,
necesitamos una manera de pasar una lista a CAR sin
que LISP trate de procesarla como llamada a funcin.
QUOTE
Con este objetivo se suministra la funcin QUOTE . Una
lista dentro de una funcin QUOTE no se tratar de
evaluar como llamada a una funcin. La llamada a la
funcin QUOTE se puede abreviar utilizando el signo
apstrofe < >.

Funciones CDR y NTH:

CDR

CDR recibe tambin una lista y devuelve el resto de la


lista despus de eliminar el primer elemento (CAR
lista). Por lo tanto puede contemplarse como la
funcin complementaria de CAR. Una manera de
interpretar una lista en LISP es como la conjuncin de
un CAR y un CDR. Se podr acceder a cualquier trmino
de una lista mediante los anidamientos apropiados de
CAR y CDR.
(CAR lista) ;primer trmino
(CAR (CDR lista)) ;segundo trmino
(CAR (CDR (CDR lista))) ;tercer trmino
y as sucesivamente... Para simplificar las expresiones se
permite crear nombres compuestos para anidamientos
de CAR y CDR de la siguiente manera:
comenzando por una primera letra C
una letra A por cada CAR o una D por cada CDR
terminando con una letra R
as (CAR (CDR (CDR lista))) sera lo mismo que
(CADDR lista).

De esta manera podemos construir hasta 28 funciones


distintas para acceso a listas. Segn Johnson* estas 28
concatenaciones se pueden dividir en cuatro grupos,
tomando como base la profundidad a que pueden
acceder en listas anidadas en varios niveles.
Funciones de acceso al nivel superior:

Funciones de acceso al segundo nivel de anidamiento:

Funciones de acceso al tercer nivel de anidamiento:

Funciones de acceso al cuarto nivel de anidamiento:

Por supuesto, que estas funciones pueden a su vez


combinarse para acceder a niveles an ms profundos
de anidacin.
NTH

NTH permite simplificar estas expresiones para listas


muy largas:
(nth n lista)
Donde el argumento n es el nmero del elemento que
debe devolverse (cero es el primer elemento). Si n es
mayor que el nmero de elemento mayor de la lista, NTH
devuelve nil .

EJEMPLOS:

De lo antes expuesto resultara:


_$ (car '(a b c))
lista normal
A
_$ (cdr '(a b c))
(B C)

;Caso de una

_$ (cddr '(a b c))


(D)
_$ (cdddr '(a b c))
;el ltimo objeto
es una lista vaca
nil
_$ (car '(a b . c))
;Caso en que la
lista termina en un par punteado
A
_$ (cdr '(a b . c))
(B . C)
_$ (cddr '(a b . c))
C
;el ltimo
objeto de la lista no es un CONS
_$ (cdddr '(a b . c))
;lo que provoca
un error
; error: bad argument type: consp C
_1$

FUNCIONES DE CONSTRUCCIN DE LISTAS

La funcin CONS

CONS es el constructor de lista bsico. Construye listas


insertando elementos en listas existentes (incluso vacas). El
nuevo elemento ocupa el primer lugar de la lista (CAR
lista).
(cons nuevo_elemento lista)
El nuevo_elemento puede ser un tomo o una lista.
La funcin CONS tambin acepta un tomo en lugar del
argumento lista, en cuyo caso construye una estructura
denominada par punteado. El CDR de un par punteado es el
segundo trmino ya extrado de la lista, es decir, sin los
parntesis.
Ejemplo: (cons 'a 'b) devuelve (A . B) y (cdr '(a . b))
devuelve B.
Debe tenerse en cuenta que CONS, al igual que casi todas las
funciones LISP es una funcin no destructiva, es decir que no

altera los argumentos que recibe. As que para conservar la


lista con el nuevo primer elemento, ser necesario utilizar
SETQ. La funcin ms general para incorporar nuevos
elementos a una lista sera entonces:
(setq nombre_lista (cons nuevo_elemento
nombre_lista))
donde nombre_lista sera el smbolo asociado al objeto lista.
la funcin opera aunque nombre_lista no hubiera sido
previamente asociado a una lista, pues no debemos olvidar
que un smbolo no asociado se evala como NIL, que es, a su
vez, equivalente a una lista vaca.
Ejemplo:
_$
(A
_$
(A
_$
(A

(cons 'a 'b)


. B)
(cons 'a (cons 'b (cons 'c '())))
B C)
(cons 'a '(b c d))
B C D)

Funciones de ejemplo usando CONS/CAR/CDR


La funcin LIST

(list expr ...)


LIST Recupera cualquier nmero de expresiones y las
combina en una lista. Admite tanto tomos como listas. Si
uno de los agumentos es una lista vaca NIL aparecer como
uno de los trminos de la lista.
Ejemplo:
_$ (list 3 4 'a (car '(b . c)) (+ 6 -2))
(3 4 A B 4)
_$ (list (list 'a 'b) (list 'c 'd 'e))
((A B) (C D E))
La funcin APPEND

(append lista lista ...)


APPEND Se utiliza para combinar listas. Elimina el primer nivel
de anidacin de cada una de las listas que recibe para

combinar todas en una misma lista. Si una de las listas que


recibe est vaca esta lista no aparecer en la lista resultante.
Ejemplo:
_$ (append '(a b c) '(d e f) '() '(g))
(A B C D E F G)
Una muestra de la utilizacin de APPEND para eliminar las
sublistas vacas:
_$ (apply 'append '(("M") ("a") nil ("r") ("i")
nil))
("M" "a" "r" "i")

OTRAS FUNCIONES PARA TRATAMIENTO DE LISTAS

REVERSE devuelve una lista con sus elementos invertidos


(reverse lista)
Opera nicamente sobre el primer nivel de anidacin. Las
listas anidadas a otros niveles no son afectadas. Suele
utilizarse para volver a su orden original los objetos en listas
construidas mediante CONS.
_$ (reverse '("M" "a" "d" "r" "i" "d"))
("d" "i" "r" "d" "a" "M")
LENGTH devuelve un nmero entero que indica el nmero de
elementos de una lista
(length lista)
Slo cuenta elementos en el primer nivel de anidacin. No se
consideran los elementos incluidos en sub-listas.
_$ (length '((0 . "CIRCLE")(8 . "0")(10 242.426
157.686 0.0)(40 . 27.7503)))
4

ASSOC
(assoc elemento lista_asoc)
Busca una lista de asociaciones de un elemento y devuelve la
entrada asociada de la lista
_$ (assoc 10 '((0 . "CIRCLE")(8 . "0")(10 242.426
157.686 0.0)(40 . 27.7503)))
(10 242.426 157.686 0.0)
SUBST
(subst elemento_nuevo elemento_antiguo lista)
Busca un elemento antiguo en una lista y devuelve una copia
de sta con un elemento nuevo en lugar de cada aparicin del
elemento antiguo.
_$ (subst nil "d" '("M" "a" "d" "r" "i" "d"))
("M" "a" nil "r" "i" nil)
_$

FUNCIONES BSICAS DE TRATAMIENTO DE CADENAS

Las funciones bsicas de tratamiento de cadenas aqu


expuestas son las incluidas con AutoLISP nativo. A ellas se
unen una serie de funciones adicionales suministradas con
Visual LISP y los API especficos de las aplicaciones
soportadas sobre AutoCAD como AutoCAD MAP.
ASCII
Devuelve el cdigo ASCII (un nmero entero) del primer
carcter de una cadena
_$ (ascii "Madrid")
77
CHR
Devuelve el carcter que corresponde al cdigo ASCII
(un nmero entero) que se ler pasa como argumento
_$ (chr 77)
"M"

STRCAT
(strcat cadena1 [cadena2] ...)
Devuelve una cadena que es la concatenacin de varias
cadenas
_$ (strcat (chr 77) "adrid")
"Madrid"
STRLEN
(strlen [cadena] ...)
Devuelve un nmero entero que indica la cantidad de
caracteres de una cadena
_$ (strlen "Madrid")
6
SUBSTR
(substr cadena inicio [longitud])
Devuelve una subcadena de una cadena
_$ (substr "Madrid" 3 2)
"dr"
STRCASE
(strcase cadena [cul])
Devuelve todos los caracteres alfabticos de una cadena
en maysculas o minsculas
_$ (strcase "Madrid")
"MADRID"
_$ (strcase "Madrid" T)
"madrid"
WCMATCH
(wcmatch cadena patrn)
Realiza bsquedas con patrones de comodines en una
cadena
_$ (wcmatch "Madrid" "?a?r*")
T
_$ (wcmatch "Madrid" "?d?r*")
nil
READ
(read [cadena])
Devuelve el primer tomo o la primera lista contenida en
una cadena
_$ (read "Madrid es una ciudad")
MADRID
_$ (read (strcat "(" "Madrid es una ciudad" ")"))
(MADRID ES UNA CIUDAD)

FUNCIONES VISUAL LISP DE TRATAMIENTO DE CADENAS

(vl-prin1-to-string object)
Devuelve la representacin como cadena de cualquier
objeto LISP tal como si fuera la salida de la funcin
PRIN1
_$ (setq file_id (open "test.tmp" "w"))
#<file "test.tmp">
_$ (vl-prin1-to-string file_id)
"#<file \"test.tmp\">"
(vl-princ-to-string object)
Devuelve la representacin como cadena de cualquier
objeto LISP tal como si fuera la salida de la funcin
PRINC
_$ (setq file_id (open "test.tmp" "w"))
#<file "test.tmp">
_$ (vl-princ-to-string file_id)
"#<file test.tmp>"
(vl-string->list string)
Convierte una cadena en una lista de cdigos de
carcter numricos ASCII
_$ (vl-string->list "Madrid")
(77 97 100 114 105 100)
(vl-string-elt string position)
Devuelve la representacin ASCII del carcter situado en
la posicin especificada en una cadena. El primer
carcter ocupa la posicin cero
_$ (vl-string-elt "Madrid" 0)
77
_$ (chr 77)
"M"
_$
(vl-string-left-trim character-set string)
Quita los caracteres especificados del inicio de una
cadena
_$ (vl-string-left-trim "PRE" "PREFIJO")
"FIJO"

(vl-string-mismatch cad1 cad2 [pos1 pos2 ignorarcaja])


Devuelve la longitud del prefijo comn ms largo para
dos cadenas (cad1 cad2), comenzando en las posiciones
que se especifican (pos1 pos2) teniendo en cuenta o no
la diferencia entre maysculas y minsculas (ignorarcaja)
_$ (vl-string-mismatch "vl-fun" "avl-var")
0
_$ (vl-string-mismatch "vl-fun" "avl-var" 0 1)
3
_$ (vl-string-mismatch "VL-FUN" "VL-VAR")
3
_$ (vl-string-mismatch "VL-FUN" "Vl-vAR")
1
_$ (vl-string-mismatch "VL-FUN" "Vl-vAR" 0 0 T)
3
(vl-string-position code-car cad [pos-inic [desdefinal]])
Busca el carcter con el cdigo ASCII especificado en
una cadena
_$ (vl-string-position 100 "Madrid")
2
_$ (vl-string-position 100 "Madrid" nil T)
5 ;a partir de la derecha se encuentra la ltima 'd'
(vl-string-right-trim conj-caracteres cadena)
Quita los caracteres especificados del final de una
cadena
_$ (vl-string-right-trim "FIJO" "PREFIJO")
"PRE"
(vl-string-search patron cadena [pos-inicial])
Busca el patrn especificado dentro de una cadena
_$ (vl-string-search "dr" "Madrid")
2
(vl-string-subst nueva-cad patron cadena [pos-inicial])
Sustituye una subcadena (patron) por otra (nueva-cad)
dentro de una cadena dada, a partir de la posicin (posinicial) especificada
_$ (vl-string-subst "leyenda" "cadena" "Una cadena
sustituida")
"Una leyenda sustituida"

_$ (vl-string-subst "esta" "cadena" "Una cadena u


otra cadena a sustituir" 0)
"Una esta u otra cadena a sustituir"
_$ (vl-string-subst "esta" "cadena" "Una cadena u
otra cadena a sustituir" 10)
"Una cadena u otra esta a sustituir"
(vl-string-translate conj-origen conj-dest cad)
Reemplaza caracteres en una cadena con un conjunto
especificado de caracteres
_$ (vl-string-translate "abcABC" "123123" "A = a, B
= b, C = C")
"1 = 1, 2 = 2, 3 = 3"
_$ (vl-string-translate "abc" "123" "A = a, B = b, C
= C")
"A = 1, B = 2, C = C"
(vl-string-trim conj-caract cadena)
Quita los caracteres especificados del inicio y del final de
una cadena
_$ (vl-string-trim "Ser" "Ser o no Ser")
" o no "

FORMAS ESPECIALES

Algunas funciones LISP se consideran como Formas


Especiales porque evalan los argumentos recibidos de
una manera diferente que la mayora de las funciones
llamadas desde Visual LISP. Una funcin tpica evala
todos los argumentos que se le pasan antes de actuar
sobre ellos. Las Formas Especiales o no evalan todos
sus argumentos, o slo evalan algunos argumentos
bajo determinadas condiciones. Por ejemplo, defun se
considera una Forma Especial, ya que tiene como
resultado el definir una nueva funcin de usuario a partir
de los argumentos que recibe, sin evaluar los mismos.
Las siguientes funciones AutoLISP y Visual LISP se
incluyen en la categora de Formas Especiales:
AND
OR
COMMAND
PROGN
COND
QUOTE

DEFUN
DEFUN-Q
FOREACH
FUNCTION
IF
LAMBDA

REPEAT
SETQ
TRACE
UNTRACE
VLAX-FOR
WHILE

FUNCIONES DEFINIDAS POR EL USUARIO

Un programa grande suele dividirse en una serie de pequeas


formas o funciones de usuario ms fciles de implementar y
depurar. Las mismas se componen a partir de llamadas a las
funciones primitivas. Estas llamadas tendrn la forma de
listas que podrn anidarse unas dentro de otras de acuerdo a
lo que requiera la complejidad de la manipulacin que quiera
realizarse de los datos aportados como argumentos. Para la
definicin de funciones de usuario normalmente utilizaremos
la forma especial DEFUN. Otra manera de representar
funciones de usuario son las expresiones LAMBDA. El estudio
de su relacin con DEFUN contribuir a una mejor
comprensin del proceso. La carga de las funciones de
usuario guardadas en ficheros se realiza mediante la funcin
LOAD. Un fichero en que se guarda un programa LISP contiene
las distintas formas o funciones de usuario, una a continuacin
de la otra, terminando por la funcin que debe invocarse para
iniciar la ejecucin del programa. Esto se debe a que la
funcin LOAD imprimir en pantalla el nombre de la ltima
forma evaluada. El nombre de esta funcin inicial se suele
comenzar con los caracteres "C:" lo que indica al sistema que
dicha funcin de usuario debe tratarse como si fuera un
comando nativo de AutoCAD, en el sentido de que pueda
invocarse tecleando el nombre (sin el prefijo "C:") sin
encerrarlo entre parntesis. Una funcin de este tipo no
admite argumentos en su lista de parmetros, aunque s la
declaracin de variables locales.

DEFUN, LAMBDA, FUNCTION y LOAD

LA PRIMITIVA DEFUN

(defun sm lista-argumentos expresin ...)


DEFUN permite definir una nueva funcin de usuario con el
nombre sm (el nombre de la funcin se incluye
automticamente en un QUOTE). Detrs del nombre de la
funcin aparece una lista de parmetros (posiblemente
vaca), con los argumentos a recibir, y que puede estar
seguida por una barra oblicua y los nombres de uno o ms
smbolos locales (variables locales) que sern definidas para
uso exclusivo de esta funcin. Esta barra oblicua debe ir
separada del primer smbolo local y del ltimo argumento, si
existe, por un espacio como mnimo. Si no declara ningn
argumento ni variable local, se debe incluir una lista vaca
tras el nombre de la funcin. Los argumentos son tratados
como una especie de variables locales en el sentido de que no
estarn disponibles fuera de la funcin. Los nombres de
argumentos deben ser nicos dentro de la misma funcin.
A continuacin de la lista de parmetros se debern incluir
todas las expresiones que debern ser evaluadas al llamar a
la nueva funcin de usuario.
A diferencia de muchas funciones primitivas AutoLISP, las
funciones definidas por el usuario no pueden tener
argumentos opcionales. Una llamada a una funcin de usuario
debe suministrar valores para todos los argumentos
declarados.
DEFUN no es una funcin normal, sino lo que se incluye entre
las llamadas formas especiales, en el sentido de que sus
argumentos no son evaluados. Lo sern ms tarde, al llamar
a la nueva funcin, sustituyendo sus argumentos por los
valores que se desea procesar.
La siguiente expresin define una funcin llamada DOBLE que
devuelve el doble de su argumento (nmero real o entero).
_$ (defun doble (x)(* x 2))
DOBLE
As hemos creado una nueva funcin Lisp que puede llamarse
desde el nivel superior o anidada en otras funciones:

_$ (doble 1)
2
Un programa Lisp usualmente incluye una coleccin de tales
defuns, asemejndose en ello a un fichero de definiciones de
procedimientos en lenguajes tales como C o Pascal.
Pero, segn puntualiza Graham, "algo muy diferente est
sucediendo aqu. Las funciones Lisp son objetos por s
mismas. Lo que realmente hace DEFUN es construir una
funcin y guardarla bajo el nombre que aparece como primer
argumento."
Podemos acceder a la funcin asociada al smbolo DOBLE
utilizando la funcin Visual LISP vl-symbol-value:
_$ (vl-symbol-value 'DOBLE)
#<USUBR @045677ac DOBLE>
En versiones anteriores de AutoLISP la funcin creada con
defun era una lista:
Command: (defun doble (x) (* x 2))
DOBLE
Command: !doble
((X) (* X 2))
Command: (car doble)
(X)
Command: (cdr doble)
((* X 2))
En Visual LISP la funcin de usuario creada con defun es una
funcin compilada que contiene instrucciones en lenguaje de
mquina, por lo tanto en Autocad 2000 obtendremos:
Command: (defun doble (x) (* x 2))
DOBLE
Command: !doble
#<SUBR @01d5ba28 DOBLE>
Command: (car doble)
; error: bad argument type: consp #<SUBR @01d5ba28
DOBLE>
Command: (cdr doble)
; error: bad argument type: consp #<SUBR @01d5ba28
DOBLE>

EXPRESIONES LAMBDA

La independencia de ambos procesos, la construccin de la


funcin y el asignarle un nombre se comprende claramente si
analizamos la funcin LAMBDA.
(lambda argumentos expr ...)
Mediante ella, podemos referirnos a una funcin literalmente
de la misma manera que lo haramos con un nmero o una
cadena de texto. Un nmero se representa a s mismo. Una
cadena se representa mediante una serie de caracteres
rodeados de comillas dobles. Para representar una funcin se
utilizan expresiones-lambda.
Una expresin-lambda es una lista de tres componentes:
1. El smbolo lambda
2. Una lista de parmetros
3. Una serie de expresiones que se evalan al ejecutar la
funcin.
Una funcin equivalente a doble es la referida por la siguente
expresin-lambda:
_$ (lambda (x)(* x 2))
#<USUBR @0344f0dc -lambda->
La forma especial setq puede servir a su vez para asignar
esta funcin a un smbolo:
_$ (setq doble (lambda (x)(* x 2)))
#<USUBR @0344f104 -lambda->
_$ (doble 4)
8
que podemos ejecutar perfectamente como funcin de
usuario.
LAMBDA suele usarse conjuntamente con APPLY y/o MAPCAR
para ejecutar una funcin sobre una lista.
FUNCTION

El operador FUNCTION le indica al compilador Visual LISP que


enlace y optimice un argumento tal como si fuera una funcin
primitiva.
(function smbolo | expresin-lambda)
FUNCTION es idntico a la funcin QUOTE excepto en que
fuerza la compilacin del argumento de la misma manera que
lo hara DEFUN. Si inclumos las funciones internas en
expresiones del tipo (function (lambda <parmetros>
<expresiones> ...) en lugar de (quote (lambda <parmetros>
<expresiones> ...)) '(lambda <parmetros> <expresiones>
...), nos aseguraremos que el cdigo sea enlazado (linked) y
optimizado en tiempo de compilacin (como una USUBR
annima) en lugar de ser simplemente evaluado en tiempo de
ejecucin. Las expresiones-LAMBDA compiladas contendrn
informacin para su depuracin al ser cargadas en el IDE
Visual LISP. Admite un argumento smbolo que nombra una
funcin y una expresin-lambda de la forma: (LAMBDA
argumentos {expresin-S}*)
Ejemplos:
El compilador Visual LISP no puede optimizar la expresin
lambda precedida de apstrofe (QUOTE) en la siguiente
expresin:
(mapcar
'(lambda (x) (* x x))
'(1 2 3))
Pero una vez incluida la expresin dentro de FUNCTION el
compilador podr optimizar la expresin lambda:
(mapcar
(function (lambda (x) (* x x)))
'(1 2 3))
Lo que redundar en un incremento de la velocidad de
ejecucin al generarse el correspondiente cdigo optimizado
en lenguaje de mquina.
LOAD

Una de las virtudes de LISP es la posibilidad de construir, a


partir de las primitivas aportadas por el lenguaje, las
funciones necesarias para el desarrollo de una aplicacin
especfica. Estas funciones operan de manera idntica a las
funciones primitivas. Si bien podemos evaluar las funciones
LISP desde la Consola de Visual LISP o desde la propia lnea
de comandos de AutoCAD, cuando se trata de funciones ms
extensas lo usual es escribirlas en un fichero de texto (con
extensin LSP) y cargarlas mediante la funcin LOAD. El IDE
(Entorno de Desarrollo Integrado) Visual LISP incluye un
editor de programacin que facilita la redaccin de programas
lisp mediante una serie de ayudas, tales como el texto
coloreado segn la sintaxis y la identacin y formateo
automtico del texto. Trabajando en este IDE se pueden
cargar las funciones o "formas" contenidas en el archivo
fuente en desarrollo mediante el correspondiente botn de
la barra de herramientas u opciones de men. La instruccin
LISP para cargar en memoria un programa LISP contenido en
un fichero es LOAD:
(load nombre_archivo [si_falla])
La funcin LOAD puede ser usada desde dentro de otra funcin
LISP e incluso de manera recursiva (en el fichero que se est
cargando).
nombre_archivo debe ser una cadena que representa el
nombre del fichero. Si no se incluye la extensin LOAD
comprobar la existencia de un fichero con ese nombre y
alguna de las siguientes extensiones en el orden que se
especifica a continuacin:

.vlx
.fas
.lsp

Se cargar el primer fichero encontrado. Si load no se ejecuta


de forma correcta, devuelve el valor del argumento si_falla.
Sin embargo, si si_falla no se especifica, un fallo de load
genera un error de Visual LISP. Si la operacin es correcta,
load devuelve el valor de la ltima expresin del archivo.
El nombre_archivo puede incluir un prefijo de directorio, como
en "/ funcin/prueba1". En los sistemas DOS tambin se

admite una letra de unidad. Una barra oblicua (/) o dos


contrabarras (\\ ) son delimitadores de directorio vlidos. Si
no incluye un prefijo de directorio en la cadena
nombre_archivo, load busca el archivo especificado en el
camino de la biblioteca AutoCAD. Si lo encuentra en cualquier
parte de este camino, load lo carga.
Si el argumento si_falla es una funcin vlida de Visual
LISP, se calcula. En la mayora de los casos, el argumento
si_falla debera ser una cadena o un tomo. Esto permite
que una aplicacin Visual LISP que llame a load tome una
accin alternativa cuando se produce un fallo.

NUEVAS FUNCIONES TRIGONOMTRICAS

Las funciones trigonomtricas que ofrece AutoLISP como


primitivas se reducen a tres: SENO, COSENO y
ARCOTANGENTE. Muchas operaciones geomtricas requerirn,
sin embargo, recurrir a otros operadores trigonomtricos.
Esto puede servir de ejemplo a la posibilidad de desarrollar
nuevas funciones utilitaria dentro de LISP.
Funciones Trigonomtricas primitivas de AutoLISP:

SIN
(sin ang)
Devuelve el seno de un ngulo expresado en radianes.
COS
(cos ang)
Devuelve el coseno de un ngulo expresado en radianes.
ATAN
(atan num1 [num2])
Devuelve el arcotangente de num1, en radianes, si se le
suministra solamente num1. Si se suministraran ambos
argumentos num1 y num2, ATAN devuelve el arcotangente
de num1/num2, en radianes. Si num2 fuera cero,
devolver un ngulo de ms o menos 1.570796 radianes

(+90 grados o 90 grados), segn el signo de num1. El


rango de ngulos devuelto es -pi/2 a +pi/2 radianes.
Funciones de conversin:

Puesto que AutoLISP trabaja con radianes mientras que


AutoCAD lo hace por defecto en ngulos sexagesimales, sera
necesario tener a mano siempre las funciones de conversin
grados-radianes.
Conversin entre grados y redianes:
;;;recibe ang en radianes y lo devuelve en grados
(defun grados (rad)
(* (/ rad pi) 180.0)
);_fin de defun
;;;recibe ang en grados y lo devuelve en radianes
(defun radianes (grd)
(* (/ grd 180.0) pi)
);_fin de defun
Las funciones trigonomtricas no incluidas con AutoLISP:

Las siguientes funciones trigonomtricas han sido publicadas


por Jon Fleming.
Autor: Jon Fleming < jonf@fleming-group.com>, Mayo
20 1997.
fuente: Grupo de Noticias
autodesk.autocad.customization
Obsrvese que:

Algunas de las funciones (ASEC -arcosecante- y ACSC


-arcocosecante-) utilizan otras funciones definidas en
este mismo archivo.
Ninguna de estas funciones comprueban la validez de los
argumentos que reciben. Esta comprobacin debe
hacerse en los programas que las invocan.
Las funciones se han desarrollado evitando la posibilidad
de un error de divisin por cero.
Se ha determinado experimentalmente que 9.7E307 es
el nmero mayor que puede ser generado en AutoLISP
(R14).

Visual LISP en Autocad 2000 (R15) y 2002 al


producirse un nmero en exceso del mayor valor real
admitido, en lugar de generar un error devuelve el
smbolo 1.#INF, que puede asignarse a una variable que
sea devuelta en caso de divisin por cero:
Podemos definir una funcin que nos devuelva este
smbolo. Para ello contamos con el predicado no
documentado VL-INFP que detecta cuando un nmero
rebasa el mximo valor admitido para los nmeros
reales:

(defun infinito ( )
(setq *INF* 2.0)
(while (not (VL-INFP *INF*))
(setq *MAX-REAL* *INF* *INF* (expt *INF* 2))))
_$ (infinito)
1.#INF
_$ *MAX-REAL*
1.34078e+154
_$ *inf*
1.#INF
as tendremos que cualquier nmero dividido entre *INF*
devolver cero y tendremos definida una variable global
*MAX-REAL* que nos permitir comprobar si un valor se
aproxima al mximo valor real admitido por el sistema:
(/ 254.98 *INF*) 0.0
TAN
acepta cualquier ngulo en radianes y devuelve la
tangente en un rango de -9.7E307+epsilon a 9.7E307,
ambos inclusive. Se analiza la posibilidad de que el
coseno del valor pasado sea igual a cero, para evitar un
error de divisin por cero.
(defun tan (z / cosz)
(if (zerop (setq cosz (cos z)))
*INF*
(/ (sin z) cosz)
) ;_fin de if
) ;_fin de defun
SEC

Acepta cualquier ngulo en radianes, devolviendo la


secante en los rangos de -9.7E307+epsilon a -1.0,
ambos inclusive y de 1.0 a 9.7E307, ambos inclusive
(defun sec (z / cosz)
(if (zerop (setq cosz (cos z)))
*INF*
(/ 1.0 cosz)
) ;_fin de if
) ;_fin de defun
CSC
Acepta cualquier ngulo en radianes, devolviendo la
cosecante en los rangos de -9.7E307+epsilon a -1.0,
ambos inclusive y de 1.0 a 9.7E307, ambos inclusive
(defun csc (z / sinz)
(if (zerop (setq sinz (sin z)))
*INF*
(/ 1.0 sinz)
)
)
ASIN (seno inverso)
acepta un argumento en el rango -1.0 a 1.0 ambos
inclusive, y devuelve un ngulo en radianes en el rango
de (-pi/2) a (pi/2) ambos inclusive.
(defun asin (z /)
(atan z (sqrt (- 1.0 (* z z))))
) ;_fin de defun
ACOS (coseno inverso)
acepta un argumento en el rango -1.0 a 1.0 ambos
inclusive, y devuelve un ngulo en radianes en el rango
de pi a 0 ambos inclusive
(defun acos (z /)
(atan (sqrt (- 1.0 (* z z))) z)
) ;_fin de defun
ASEC (secante inversa)
acepta un argumento en uno de dos rangos: menos
infinito a -1 ambos inclusive o 1 a infinito, ambos
inclusive, y devuelve un ngulo en radianes en el rango
de pi a 0, ambos inclusive (excepto EXACTAMENTE pi/2
que nunca ser devuelto en un ordenador con precisin
numrica finita)
(defun asec (z /)

(acos (/ 1.0 z))


) ;_fin de defun
ACSC (cosecante inversa)
acepta un argumento en uno de dos rangos: menos
infinito a -1, ambos inclusive o 1 a infinito, ambos
inclusive, y devuelve un ngulo en radians en el rango
-pi/2 a pi/2, ambos inclusive (excepto EXACTAMENTE
0.0 que nunca ser devuelto en un ordenador con
precisin numrica finita)
(defun acsc (z /)
(asin (/ 1.0 z))
) ;_fin de defun
ACOT (cotangente inversa)
acepta un argumento en el rango de menos infinito a
ms infinito, ambos inclusive y devuelve un ngulo en
radianes en el rango de pi a 0, ambos inclusive.
(defun acot (z /)
(- (/ pi 2.0) (atan z))
) ;_fin de defun

EXPRESIONES LAMBDA

La independencia de ambos procesos, la construccin de la


funcin y el asignarle un nombre se comprende claramente si
analizamos la funcin LAMBDA.
(lambda argumentos expr ...)
Mediante ella, podemos referirnos a una funcin literalmente
de la misma manera que lo haramos con un nmero o una
cadena de texto. Un nmero se representa a s mismo. Una
cadena se representa mediante una serie de caracteres
rodeados de comillas dobles. Para representar una funcin se
utilizan expresiones-lambda.
Una expresin-lambda es una lista de tres componentes:
1. El smbolo lambda
2. Una lista de parmetros

3. Una serie de expresiones que se evalan al ejecutar la


funcin.
Una funcin equivalente a doble es la referida por la siguente
expresin-lambda:
_$ (lambda (x)(* x 2))
#<USUBR @0344f0dc -lambda->
La forma especial setq puede servir a su vez para asignar
esta funcin a un smbolo:
_$ (setq doble (lambda (x)(* x 2)))
#<USUBR @0344f104 -lambda->
_$ (doble 4)
8
que podemos ejecutar perfectamente como funcin de
usuario.
LAMBDA suele usarse conjuntamente con APPLY y/o MAPCAR
para ejecutar una funcin sobre una lista.

FUNCTION

El operador FUNCTION le indica al compilador Visual LISP que


enlace y optimice un argumento tal como si fuera una funcin
primitiva.
(function smbolo | expresin-lambda)
FUNCTION es idntico a la funcin QUOTE excepto en que
fuerza la compilacin del argumento de la misma manera que
lo hara DEFUN. Si inclumos las funciones internas en
expresiones del tipo (function (lambda <parmetros>
<expresiones> ...) en lugar de (quote (lambda <parmetros>
<expresiones> ...)) '(lambda <parmetros> <expresiones>
...), nos aseguraremos que el cdigo sea enlazado (linked) y
optimizado en tiempo de compilacin (como una USUBR
annima) en lugar de ser simplemente evaluado en tiempo de

ejecucin. Las expresiones-LAMBDA compiladas contendrn


informacin para su depuracin al ser cargadas en el IDE
Visual LISP. Admite un argumento smbolo que nombra una
funcin y una expresin-lambda de la forma: (LAMBDA
argumentos {expresin-S}*)
Ejemplos:
El compilador Visual LISP no puede optimizar la expresin
lambda precedida de apstrofe (QUOTE) en la siguiente
expresin:
(mapcar
'(lambda (x) (* x x))
'(1 2 3))
Pero una vez incluida la expresin dentro de FUNCTION el
compilador podr optimizar la expresin lambda:
(mapcar
(function (lambda (x) (* x x)))
'(1 2 3))
Lo que redundar en un incremento de la velocidad de
ejecucin al generarse el correspondiente cdigo optimizado
en lenguaje de mquina.

LOAD

Una de las virtudes de LISP es la posibilidad de construir, a


partir de las primitivas aportadas por el lenguaje, las
funciones necesarias para el desarrollo de una aplicacin
especfica. Estas funciones operan de manera idntica a las
funciones primitivas. Si bien podemos evaluar las funciones
LISP desde la Consola de Visual LISP o desde la propia lnea
de comandos de AutoCAD, cuando se trata de funciones ms
extensas lo usual es escribirlas en un fichero de texto (con
extensin LSP) y cargarlas mediante la funcin LOAD. El IDE
(Entorno de Desarrollo Integrado) Visual LISP incluye un
editor de programacin que facilita la redaccin de programas

lisp mediante una serie de ayudas, tales como el texto


coloreado segn la sintaxis y la identacin y formateo
automtico del texto. Trabajando en este IDE se pueden
cargar las funciones o "formas" contenidas en el archivo
fuente en desarrollo mediante el correspondiente botn de
la barra de herramientas u opciones de men. La instruccin
LISP para cargar en memoria un programa LISP contenido en
un fichero es LOAD:

(load nombre_archivo [si_falla])


La funcin LOAD puede ser usada desde dentro de otra funcin
LISP e incluso de manera recursiva (en el fichero que se est
cargando).
nombre_archivo debe ser una cadena que representa el
nombre del fichero. Si no se incluye la extensin LOAD
comprobar la existencia de un fichero con ese nombre y
alguna de las siguientes extensiones en el orden que se
especifica a continuacin:

.vlx
.fas
.lsp

Se cargar el primer fichero encontrado. Si load no se ejecuta


de forma correcta, devuelve el valor del argumento si_falla.
Sin embargo, si si_falla no se especifica, un fallo de load
genera un error de Visual LISP. Si la operacin es correcta,
load devuelve el valor de la ltima expresin del archivo.
El nombre_archivo puede incluir un prefijo de directorio, como
en "/ funcin/prueba1". En los sistemas DOS tambin se
admite una letra de unidad. Una barra oblicua (/) o dos
contrabarras (\\ ) son delimitadores de directorio vlidos. Si
no incluye un prefijo de directorio en la cadena
nombre_archivo, load busca el archivo especificado en el
camino de la biblioteca AutoCAD. Si lo encuentra en cualquier
parte de este camino, load lo carga.
Si el argumento si_falla es una funcin vlida de Visual
LISP, se calcula. En la mayora de los casos, el argumento
si_falla debera ser una cadena o un tomo. Esto permite
que una aplicacin Visual LISP que llame a load tome una
accin alternativa cuando se produce un fallo.

ESTRUCTURAS DE CONTROL

Los predicados son funciones que devuelven respuestas


lgicas (cierto-falso), mientras que las estructuras de control
controlan la ejecucin del programa y permiten mltiples
ramificaciones.
PREDICADOS
Permiten comprobar caractersticas relacionadas con el
tipo de dato con que se est operando en cada
momento. Devuelve T (cierto) si la condicin se cumple
y nil (falso) en caso contrario.
PREDICADOS GENERALES: Suelen distinguirse
por terminar el nombre de la funcin en la letra P
que significa predicado. Se utiliza la siguiente regla
para decidir si la P est precedida por un guin: si
el nombre del predicado se forma aadiendo la P a
un nombre existente, tal como el nombre de un
tipo de dato, se aade un guin slo en el caso de
que el nombre original incluya alguno (BOUNDP,
LISTP, NUMBERP sin guin VL-FILE-DIRECTORYP, VLAX-ERASED-P con guin). Los predicados que
fueron introducidos con Visual LISP se conocen por
los prefijos que se adicionan VL-, VLAX- o VLR(VL-CONSP, VLAX-PROPERTY-AVAILABLE-P, VLRADDED-P). En casos como VL-CONSP se hace una
excepcin a la regla anterior, puesto que en
realidad se est renombrando un predicado
standard de Common LISP.
PREDICADOS SOBRE TOMOS Y LISTAS
PREDICADOS ARITMTICOS: Corresponden a
las funciones de comparacin (mayor que, menor
que, igual a...).
OTROS PREDICADOS DEFINIDOS POR EL
USUARIO: muestra de la extensibilidad de LISP.
OPERADORES LGICOS

Corresponden a las operaciones Booleanas bsicas. LISP


suministra tres operadores sobre valores Booleanos:
and, or, y not. De ellos, and y or son tambin en cierto
modo estructuras de control ya que sus argumentos son
evaluados condicionalmente. Permiten agrupar las
condiciones de prueba, casi siempre a partir de la
utilizacin de predicados que se utilizan dentro de las
estructuras de programacin descritas ms adelante.La
funcin not tiene un slo argumento que analizar, y es
por ello una funcin simple.
ESTRUCTURAS CONDICIONALES
Visual LISP provee las dos estructuras de control
tradicionales de LISP. La estructura condicional de ms
tradicin en LISP es COND. Sin embargo IF resulta ms
simple y es directamente comparable a las estructuras
condicionales de otros lenguajes de programacin.

PREDICADOS GENERALES:

TOMOS O LISTAS
o TOMOS SIMBLICOS
o TOMOS NUMRICOS
LISTAS VACAS O CONSES
IGUALDAD O IDENTIDAD

TOMOS O LISTAS:

ATOM
Sabemos que dentro de las expresiones LISP se
distinguen los tomos y las listas. El predicado ATOM
verifica si un elemento determinado es un tomo
(atom elemento)
Devuelve nil si elemento es una lista y devuelve T en
caso contrario. Debe tenerse cuidado, si se trata de un
tomo simblico, en tener claro si lo que se quiere
evaluar es el sbolo o su contenido. Si no est precedido
de QUOTE <'>, lo que se evala es el valor asociado:

_$ (atom
T
_$ (atom
T
_$ (setq
(A B C)
_$ (atom
nil
_$ (atom
T

a)
'a)
a '(a b c))
a)
'a)

LISTP
Comprueba si un elemento es una lista
(listp elemento)
Devuelve T si elemento es una lista y devuelve nil en
caso contrario. Obsrvese que como NIL es una lista
vaca, (listp nil) devolver T. Es decir, que todo
tomo simblico no asociado a un valor, devover T
tanto para ATOM como para LISTP:
_$ !b
nil
_$ (atom b)
T
_$ (listp b)
T
_$ (listp 'b)
nil
TOMOS SIMBLICOS:

VL-SYMBOLP
Identifica si un objeto especificado es o no un smbolo.
(vl-symbolp objeto)
Devuelve T si el objeto es un smbolo y nil si se trata de
una constante (nmero o cadena) o una lista.
Este predicado ha sido incorporado por Visual LISP
_$ (vl-symbolp 'a)
T
_$ (vl-symbolp 15)

nil
_$ (vl-symbolp "abc")
nil
_$ (vl-symbolp '(a b c))
nil
BOUNDP
Cuando se trata de un tomo simblico, puede ser
necesario determinar si tiene asociado un valor. BOUNDP
verifica la existencia de dicha asociacin.
(boundp sm)
Devuelve T si sm tiene un valor asociado. Si no hay
ningn valor asociado a sm (o se ha asociado a nil),
boundp devuelve nil. Si sm es un smbolo no definido,
se crea y se asocia a nil de forma automtica.

NUMRICOS:

NUMBERP
Los tomos no simblicos o constantes pueden ser
nmeros o cadenas. NUMBERP comprueba si el objeto es
un nmero (real o entero)
(numberp elemento)
Devuelve T si elemento es un valor numrico y devuelve
nil en caso contrario. El predicado complementario
STRINGP, que comprobara si se trata de una cadena no
est definido en Visual LISP, aunque se puede encontrar
entre los mensajes de error a la hora de depurar un
programa. En el ejemplo que sigue el mensaje "STRINGP

2" significara que se ha recibido un valor numrico (2)


en lugar del argumento esperado del tipo cadena.
_$ (strcat 2 "b")
; error: bad argument type:
stringp 2
MINUSP
Tratndose de valores numricos en ocasiones se deber
comprobar si son negativos. MINUSP realiza dicha
comprobacin.
(minusp nmero)
Devuelve T si nmero es negativo y nil en caso
contrario. Si el argumento no es numrico se recibir un
mensaje de error.
ZEROP
Igual que en el caso anterior, cuando se trata de valores
numricos ZEROP permite comprobar si un elemento se
evala como cero
(zerop nmero)
Devuelve T si nmero es cero y nil en caso contrario.
LISTAS VACAS O CONSES:

En LISP el valor asociado al smbolo NIL (condicin de


falso) es la lista vaca <'()>. Cualquier smbolo que
evale como NIL, devolver T (cierto) al pasarlo al
predicado LISTP. Para comprobar que se trata
efectivamente de una lista, pero que dicha lista contiene
algo (aunque fuera NIL) en las versiones anteriores de
AutoLISP era necesario utilizar adems de LISTP otros
predicados tales como BOUNDP o NULL.
NULL
Comprueba si un elemento est definido como nil
(null elemento)
Devuelve T si elemento est asociado a nil y devuelve
nil en caso contrario.
Puede emplearse para probar si se ha alcanzado el fin de
una lista en sustitucin del predicado ENDP de Common
Lisp que falta en Visual LISP

_$ (null (caddr '(a b)))


T
VL-CONSP
La situacin descrita en el prrafo anterior se resuelve
empleando en su lugar el predicado CONSP (vl-consp
para Visual LISP), que comprueba si el elemento
analizado evala como una lista no nula
(vl-consp elem-lista)
Devuelve T, si elem-lista es una lista y no est vaca,
de lo contrario devuelve nil. El trmino CONSP se
deriva de la funcin bsica de construccin de listas, que
es la funcin CONS. Una lista no vaca es el resultado de
aplicar, al menos una vez la funcin CONS.
Este predicado ha sido incorporado por Visual LISP
_$ (vl-consp a)
nil
_$ (setq a (cons 1 a))
(1)
_$ (vl-consp a)
T
El valor contenido en la lista puede incluso ser una lista
vaca:
_$ (setq b (cons nil b))
(nil)
_$ (vl-consp b)
T
_$ (vl-consp '(())) ;equivalente
a la lnea anterior
T
PERTENENCIA A UNA LISTA:

MEMBER
Es un tipo particular de predicado, que comprueba si un
tomo pertenece a una lista dada.
(member expr lista)
Si expr no aparece en la lista, member devuelve NIL. En
caso de encontrarlo, devuelve el resto de la lista, desde

el primer caso de la expresin encontrada. Lo devuelto


por MEMBER acta como T (cierto) ya que cualquier valor
no nulo actuar como la negacin de NIL (not NIL), es
decir, cierto. Debe tenerse cuidado en el caso de los
tomos simblicos de pasar el nombre del smbolo
precedido de QUOTE <'>.
_$ (member a '(c d 2 4 a '(a b)
"a" 3.0 j))
nil
_$ (member 'a '(c d 2 4 a '(a b)
"a" 3.0 j))
(A (QUOTE (A B)) "a" 3.0 J)
IGUALDAD O IDENTIDAD

Dos expresiones pueden considerarse iguales sin


necesidad de que sean idnticas. Los predicados EQUAL y
EQ permiten comprobar estas situaciones.
EQUAL
Determina si dos expresiones son iguales
(equal expr1 expr2 [aproximacin])
La funcin equal determina si expr1 y expr2 se evalan
igual. Cuando se comparan dos nmeros reales (o dos
listas de nmeros reales, como en el caso de los
puntos), los dos nmeros idnticos pueden presentar
ligeras diferencias derivadas de los mtodos utilizados
para su clculo. Para resolver esta situacin, puede
utilizarse un argumento numrico optativo,
aproximacin, para especificar la diferencia mxima que
se puede admitir entre expr1 y expr2, para que sigan
considerndose iguales.
EQ
Determina si dos expresiones son idnticas
(eq expr1 expr2)
La funcin eq determina si expr1 y expr2 estn
asociadas al mismo objeto (si apuntan a la misma
direccin de memoria). Devuelve T si las dos
expresiones son iguales y nil en caso contrario.

_$ (setq a (list 'm 'n 'o))


(M N O)
_$ (setq b (list 'm 'n 'o))
(M N O)
_$ (equal a b) ;las listas
representadas por a y b son iguales
T
_$ (eq a b)
;pero NO son la
misma lista
nil
_$ (eq (cons 'a 'b) (cons 'a
'b))
nil
;cada llamada a
cons crea una nueva lista
_$ (eq '(a . b) '(a . b))
nil
En el caso de los valores constantes, equal y eq
devuelven resultados similares, salvo lo explicado
respecto a los nmeros reales.
_$ (setq a 8)
8
_$ (setq b (+ 5 3))
8
_$ (eq a b)
T

PREDICADOS ARITMTICOS

Todos los argumentos pueden ser nmeros o cadenas.


COMPARACIONES BSICAS:

Permiten comparar nmeros o cadenas.


> (mayor que...)

Devuelve T si cada argumento es numricamente mayor


que el situado detrs de l y nil en caso contrario
(> cadnm [cadnm] ...)
< (menor que...)
Devuelve T si el primer argumento es numricamente
menor o igual que el situado detrs de l y nil en caso
contrario
(< cadnm [cadnm] ...)
=(igual que...)
Devuelve T si todos los argumentos son numricamente
iguales; de lo contrario, devuelve nil
(=cadnm [cadnm] ...)
/=(desigual a...)
Equivale a (not (=cadnm [cadnm] ...))
PREDICADOS COMPUESTOS:

(<=cadnm [cadnm] ...)


Devuelve T si cada argumento es numricamente menor
o igual que el situado detrs de l y nil en caso contrario
(> cadnm [cadnm] ...)
Devuelve T si cada argumento es numricamente mayor
que el situado detrs de l y nil en caso contrario
(>=cadnm [cadnm] ...)
Devuelve T si cada argumento es numricamente mayor
o igual que el situado detrs de l y nil en caso contrario

OPERADORES LGICOS

NOT
Negacin lgica. Cualquier expresin cuyo valor no sea
NIL evala como falsa. En cambio, (not NIL) evala
como T. Esto sucede puesto que cualquier cosa que no
tenga el valor NIL (o la lista vaca) evala en LISP como
T (cierto).
OR

Devuelve el OR lgico de una lista de expresiones


(or expr...)
La funcin o calcula las expresiones de izquierda a
derecha en busca de una expresin distinta de nil. Si la
encuentra, OR deja de realizar clculos y devuelve T. Si
el valor de todas las expresiones es nil, or devuelve nil.
AND
Devuelve el operador lgico AND de una lista de
expresiones
(and expr ...)
Si alguna de las expresiones da como resultado nil, se
interrumpe la operacin y la funcin devuelve nil; en
caso contrario, devuelve T.

FUNCIONES LGICAS BINARIAS

Si un tema ha sido poco explicado en los manuales de


programacin LISP para AutoCAD, al menos, en los que se
puede consultar en espaol, que no son muchos, es la
utilizacinde los operadores lgicos binarios. Su importancia y
posibilidades de aplicacin son inversamente proporcionales a
esa escasa atencin que se le dedica. Su uso permite la
gestin de una multitud de parmetros de la aplicacin que
estn codificados como nmeros en formato binario.
Uno de estos parmetros es el de las referencias a objeto. El
valor de la variable de sistema OSMODE es el equivalente
decimal de un nmero binario. Al nmero binario 0000 0001
corresponde la referencia punto FINal y al nmero binario 0000
0100 corresponde la referencia CENtro. Si el valor de
OSMODE fuera equivalente al nmero binario 0000 0101 eso
significara que estn activas a la vez las referencias punto
FINal y CENtro.
Cada posicin de un nmero binario representa un BIT. Un
BIT es la unidad de informacin mnima que es capaz de
manejar un computador, y slo puede uno de dos valores,
ACTIVADO o DESACTIVADO, que en su representacin

numrica simbolizamos mediante 1 0. Por eso decimos que


en la referencia punto FINal se ACTIVA el primer BIT y para la
referencia CENtro se ACTIVA el tercer BIT. El valor binario
1111 1111 1111 activara todas las referencias a objeto
posibles.
Dicho as resulta secillo, pero las dificultades comienzan
cuando tenemos en cuenta que AutoCAD espera recibir no
esta representacin a base de ceros y unos, sino su
equivalente en formato DECIMAL. Y el equivalente dcimal de
cada BIT vendra dado por 2(n-1) dinde n sera la la posicin
del bit cuyo valor decimal se desea. Expresado en trminos
de una funcin LISP (expt 2 (1- n)).
Las operaciones lgicas sobre nmeros binarios disponibles en
Visual LISP son cuatro:

~ (NOT binario)
LOGAND (AND lgico binario)
LOGIOR (OR lgico binario)
BOOLE (operador lgico binario de carcter
general)

A estas operaciones debemos aadir la funcin LSH,


desplazamiento binario, que ser la primera funcin que
estudiaremos.

SISTEMA BINARIO

Internamente, la mquina computadora representa los


valores numricos mediante grupos de bits. agrupados en
bytes. Por ejemplo, el nmero 3 se representa mediante un
byte que tiene "activos" los bits primero y segundo (contando
desde la derecha); 00000011. Esta sera la forma de
representacin del nmero 3 en un sistema numrico de base
2, tambin conocido como BINARIO. El sistema que
utilizamos normalmente es un sistema DECIMAL o de base
10. En un sistema DECIMAL, contamos desde el 0 hasta el 9
antes de aadir un nuevo dgito. El nmero 22 en un sistema

decimal significa que tenemos dos conjuntos de 10s y 2


conjuntos de 1s.
En un sistema BINARIO slo pueden haber dos valores para
cada dgito: ya sea un 0=DESACTIVADO un 1=ACTIVADO.
Para representar el nmero 22 en notacin BINARIA lo
haramos como 00010110, notacin que se explica segn la
siguiente tabla:
Posicin del BIT: 7
Valor Binario: 0
Valor Decimal: 128
Valores a Sumar: 0
Valor Resultante: 16 +

6 5 4
0 0 1
64 32 16
0 0 16
4 + 2=22

3
0
8
0

2
1
4
4

1
1
2
2

0
0
1
0

Todos los valores que corresponden a posiciones a las que se


asigna el valor binario de 0 (cero) no se cuentan, ya que 0
representa DESACTIVADO.
De la misma manera, los nmeros que corresponden a las
posiciones con valor binario 1 se sumarn, (16 + 4 + 2=22)
ya que 1 representa ACTIVADO.
Valores Decimales y sus equivalentes Binarios:

POSICIN
VALOR
BIT DECIMAL
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
16
12
32
13
64
14
100
15
256

VALOR
BINARIO
1
10
11
100
101
110
111
1000
1001
1010
10000
100000
1000000
1100100
100000000

16
17
18

512 1000000000
1000 1111110100
1024 10000000000

Bits, Bytes y Palabras...

Se suelen escribir los nmeros binarios como una secuencia


de grupos de cuatro bits, tambin conocidos como NIBBLES.
Segn el nmero de estas agrupaciones los nmeros binarios
se clasifican como:
Unidad: Nm. bits
Ejemplo:
Bit
1
1
Nibble
4
0101
Byte (Octeto)
8
0000 0101
Palabra
16
0000 0000 0000 0101
Doble Palabra
32 0000 0000 0000 0000 0000 0000 0000 0101

Los computadores personales con el sistema operativo MS


DOS utilizaban palabras de 16 BITS. Los sistemas operativos
actuales sobre los que corre AutoCAD 2000 utilizan Palabras
de 32 BITS.

Funcin LSH

Para el clculo del valor decimal de un determinado BIT sera


ms adecuado, como veremos ms adelante, utilizar la
funcin LSH. Sgn la explicacin de Reini Urban*:
(lsh <integer> <num>)
LSH quiere decir Left-SHift, en ingls desplazamiento a la
izquierda. Si se interpreta el nmero entero como una matriz
de bits ("bit-array") podemos interpretar LSH como el
desplazamiento de la matriz n-veces a la izquierda
(insertando ceros a la derecha)
Ejemplo:

int: 9 = 8+1 =>


(1 0 1) como "bit-array" (2^3 +
2^0)
(lsh 9 1)
=> (1 0 1 0) que es (2^4 + 2^1) = 18.
Fcil, puesto que (LSH i 1) es siempre igual a i*2
LSH con un nmero negativo es un desplazamiento a la
derecha (suprimir el bit ms a la derecha). (LSH i -1) es lo
mismo que i/2 ( i dividido entre 2, "divisin de enteros")
De acuerdo con esto el valor decimal del primer BIT vendra
dado por (lsh 1 0) equivalente a 0000 0001 y devolvera el
valor decimal 1. Con un desplazamiento de dos a la izquierda
obtendramos 0000 0100 que ya hemos visto que equivale a
OSMODE CENtro y (lsh 1 2) devuelve el valor decimal de 4.
Con LSH podemos disear la funcin utilitaria siguiente, que
nos devuelve el valor decimal de cualquier BIT:
(defun bit (posicion)
(lsh 1 (1- posicion))
)
De manera que (bit 1) devolvera 1, (bit 5) devolvera
16, etc.
Con lo que tenemos una manera sencilla de dar el valor
decimal que corresponde a la posicin de cualquier bit.
Activar el bit 8 (referencia PERpendicular) significara sumar
(bit 8) al valor actual de OSMODE:
(setvar "osmode" (+ (getvar "osmode")(bit 8)))
Claro que sera lo mismo
(setvar "osmode" (+ (getvar "osmode") 128))
e incluso:
(setvar "osmode" (+ (getvar "osmode") (expt 2 8)))
Pero (bit 8) resulta ms fcil de memorizar y seguramente
ms claro en cuanto a la intencin del programador. Debo
advertir que la cosa no es tan sencilla, pues debemos primero
haber comprobado que el bit 8 no estaba ya activado. Ms

adelante veremos cmo hacerlo valindonos de los


operadores LOGAND y LOGIOR.
Pero si continuamos incrementando los valores que pasamos
a la funcin BIT, descubriremos que hay un lmite:

Como se puede ver, cuando se activa el bit 32 (en un sistema


operativo de 32 bits) es decir, cuando la ltima posicin a la
izquierda de la palabra toma el valor de 1, su signo pasa a
negativo y un nuevo desplazamiento a la izquierda devolvera
de nuevo el valor del primer bit.
Esta propiedad nos permite definir una funcin para
determinar la longitud de palabra del sistema operativo
actual:
(defun LongPalabra ( / pos)
(setq pos 0)
(while (not (minusp (lsh 1 pos)))
(setq pos (1+ pos))
)
(alert (strcat "Longitud de Palabra:\n\t" (itoa
(1+ pos)) " Bits"))
)
En AutoCAD 2000 obtendramos como resultado:

Es inportante tener esto en cuenta para comprender el


funcionamiento del prximo operador a estudiar, el NOT
lgico binario (~ num).
* De: Reini Urban < rurban@sbox.tu-graz.ac.at>
Newsgroup: autodesk.autocad.customization
Asunto: Logand, logior, lsh, etc...
Fecha: Jueves, 03 Mar 1998 00:13:08 +0100
Traduccin del ingls: Reinaldo Togores

Funcin ~ (NOT lgico binario)*

Esta funcin resulta especialmente incomprensible si


consultamos los manuales AutoLISP habituales, incluyendo la
"ayuda" que viene con el programa. Nos dirn que "esta
funcin devuelve la negacin lgica de una cifra binaria, es
decir, el complemento a uno". Y se nos ilustra con ejemplos
como:
(~ 3) devuelve -4
Si bien la explicacin es del todo correcta, a los que no
poseemos conocimientos matemticos tan completos no nos
aprovecha gran cosa esa explicacin. Para encontrar una
respuesta ms comprensible hemos tenido que recurrir al
viejo manual de Nelson Johnson** cuya traduccin al espaol
fuera publicada en 1990 por McGraw-Hill. Explica Johnson
que:
(~ <nmero>)
Puede que deseemos verificar un nmero para encontrar su
funcin NOT bit a bit. En este caso, se invierten todos los bits.
el valor devuelto por la funcin "~" ser un nmero que tenga
todos los bits a 0 del argumento puestos a 1 y, viceversa,
todos los bits del argumento que estaban a 1 estarn a cero.
El nmero 9 en binario sera 1001, o mejor, considerando un
tamao de palabra de 32 bits:
0000 0000 0000 0000 0000 0000 0000 1001

(~ 9) devolvera -10
Lo que sera igual en nmeros binarios con tamao de palabra
de 32 bits a:
1111 1111 1111 1111 1111 1111 0110
El valor negativo se explica, segn lo dicho al explicar la
funcin LSH, al ocupar la posicin extrema izquierda un valor
1. La posibilidad de construir este "filtro negativo" de un valor
binario es extremadamente valioso para gestionar los valores
guardados en trminos de posiciones de bits.
Pero para la gestin de estos valores binarios nos deberemos
auxiliar de otras funciones como LOGAND, LOGIOR, y
BOOLE
No es muy frecuente el uso de esta funcin en los programas
LISP dentro de AutoCAD. Revisando los programas
suministrados con la aplicacin podemos encontrar ejemplos
de su uso en AI_UTILS.LSP y DDMODIFY.LSP de las
versiones 13 y 14 y FORMAT.LSP de la versin 12.

* En los computadores que se utilizan en Espaa el carcter ~


(tilde) se ha suprimido para incluir en su lugar la letra . Para
escribir el carcter tilde ser necesario utilizar la combinacin
de teclas ALT 126, es decir, manteniendo pulsada la tecla
ALT teclear 126 en el teclado numrico.
** Johnson, Nelson. AutoCAD: Manual de Referencia.
Osborne/McGraw-Hill, Madrid, 1990. ISBN 84-7615-451-8

LOGAND

Para LOGAND transcribimos la explicacin de Jon Fleming *


en el mismo hilo de discusin donde fu expuesta la
explicacin anterior de Reini Urban:

(logand 13 22) es el AND lgico de [8 + 4 + 1] con [16 +


4 + 2] o, escribiendo los nmeros en binario, de 00001101
con 00010110.
Escribiendo los nmeros uno sobre el otro, podemos entonces
escribir la respuesta en binario de inmediato, escribiendo un 1
bajo dos nmeros uno y un 0 en cualquier otro lugar:
13 =
22 =
13 y 22 =

00001101
00010110
00000100

es decir, 4 en notacin decimal. Por lo tanto, (logand 13 22)


devuelve 4. El AND lgico se suele utilizar como filtro. Uno de
los nmeros que definimos contendr un 1 en su
representacin binaria dondequiera que deseamos que un
posible 1 en un nmero desconocido pase por el filtro. Esto
se debe a que un entero es un lugar muy eficiente para
guardar varios valores lgicos verdadero/falso relacionados
como unos y ceros en posiciones definidas en la
representacin binaria de un entero.
Un ejemplo perfecto lo constituye la variable de sistema
OSMODE. Queremos saber si la referencia a objeto
INTERSECCIN se encuentra activa? Nuestra referencia de
comandos nos dice que la presencia de 32 en el valor de
OSMODE indica la referencia INTERSECCIN. Como slo nos
interesa la referencia INTERSECCIN, escribimos la
representacin binaria de OSMODE con "x" en las posiciones
que no interesa comprobar: El valor de OSMODE podra ser:
xxxxxx1xxxxx
o: xxxxxx0xxxxx
As que si pasamos a (logand ...) cualquiera de esos
valores con 0000 0010 0000 que es 32 en base 10,
obtenemos, ya sea 32 (si est activa la referencia
INTERSECCIN) o 0 (cero) si no lo est. En otras palabras:
(if (logand 32 (getvar "OSMODE"))
(prompt "\nLa referencia INTERSECCIN est
ACTIVA")

(prompt "\nLa referencia INTERSECCIN NO est


ACTIVA")
)
Utilizando las funciones LSH, ~ y LOGAND pudiramos
desarrollar funciones para la conversin de decimales en
binarios y viceversa, tiles al menos para comprender mejor
la operacin de estas funciones binarias. Este ser el tema de
la prxima seccin.
Los ejemplos de LOGAND en los programas LISP que vienen
con AutoCAD s son numerosos. Podemos enumerar para la
versin 14: BMAKE.LSP, DDATTDEF.LSP, DDGRIPS.LSP,
ATTREDEF.LSP, DDCHPROP.LSP, DDCOLOR.LSP,
DDINSERT.LSP, DDMODIFY.LSP, DDPTYPE.LSP,
DDSELECT.LSP, DDUNITS.LSP, DDVIEW.LSP, 3D.LSP,
EDGE.LSP, MVSETUP.LSP, BLK_LST.LSP, COUNT.LSP,
LMAN.LSP, TREXBLK.LSP, CLIPIT.LSP, EXCHPROP.LSP,
EXTRIM.LSP, XPLODE.LSP, CURSDLG.LSP,
SQLEDDLG.LSP.
Mucchos de estos programas ya aparecan en la versin 13.
Para indicar alguno de aquella versin que ha desaparecido
desde entonces podemos mencionar DDOSNAP.LSP.
Enumerando slo algunos de la versin 12 tendramos:
CHELEV.LSP, MAKE2D.LSP, MAKE3D.LSP, PTEXT.LSP,
CL.LSP y PROJECT.LSP, y de la versin 10 TABLES.LSP, lo
que nos puede dar una idea de lo til que resulta esta
funcin.
* De: Jon Fleming < jonf@fleming-group.com>
Newsgroup: autodesk.autocad.customization
Asunto: Logand, logior, lsh, etc...
Fecha: Jueves, 26 Feb 1998 20:35:37 EST
Organizacin: The Fleming Group
Traduccin del ingls: Reinaldo Togores
CONVERSIN ENTRE BINARIOS Y DECIMALES (I)

CONVERSIN DECIMAL->BINARIO

Aplicando lo visto hasta ahora podemos crear una funcin que


convierta cualquier nmero decimal, positivo o negativo, en
su representacin binaria.
El manual de Personalizacin de AutoCAD * propone una
solucin, pero que es aplicable slo a enteros positivos:
;;;Del manual de Personalizacin:
;;;convierte un entero POSITIVO a una cadena
;;;en la base dada:
(defun base (bas int / ret yyy zot)
(defun zot (i1 i2 / xxx)
(if
(> (setq xxx (rem i2 i1)) 9)
(chr (+ 55 xxx))
(itoa xxx)
) ;_ fin de if
) ;_ fin de defun
(setq
ret (zot bas int)
yyy (/ int bas)
) ;_ fin de setq
(while (>= yyy bas)
(setq ret (strcat (zot bas yyy) ret))
(setq yyy (/ yyy bas))
) ;_ fin de while
(strcat (zot bas yyy) ret)
) ;_ fin de defun
Para nmeros enteros positivos opera correctamente pero no
as para los negativos, como puede verse en los siguientes
ejemplos:

Nuestra funcin BINARIO tiene en cuenta la longitud de


palabra del sistema operativo y devuelve la secuencia
correcta de ceros y unos incluso cuando se trate de valores
negativos. La funcin espera recibir un entero, pero prev el
caso de un nmero real, truncndolo al entero menor ms

cercano.
Se definen las funciones utilitarias BIT y POSBIT, esta ltima
utilizada para guardar el valor de la posicin del bit que se
analiza. La conversin en s misma la realiza la funcin
ConvierteBinario que recibe como argumentos el nmero a
convertir y una funcin predicado a plicar segn el nmero
sea positivo o negativo.
Esta funcin de conversin es llamada desde la funcin
principal BINARIO que analiza si el nmero recibido es
positivo o negativo. En caso de ser negativo pasa a la funcin
de conversin su NOT lgico (~ numdec) y el predicado '= en
lugar del nmero recibido y el predicado '/= que pasara en
caso de ser el nmero positivo.
;;;Binario.lsp
;;;El ciclo continuar hasta que LSH devuelva un
valor negativo
;;;significando que se ha llegado al final de la
palabra (posicin
;;;extrema izquierda). El valor binario es devuelto
en formato de lista.
;;;
;;; Funcin auxiliar Bit: devuelve el valor decimal
del bit en la posicin indicada.
;;;
(defun Bit (pos) (lsh 1 (1- pos)))
;;;
;;;
;;Funcin utilizada como acumulador del valor de la
posicin
;;;
(defun PosBit ()
(if (null posicion)
(setq posicion 1)
(setq posicion (1+ posicion))
) ;_ fin de if
) ;_ fin de defun
;;;
;;;
;;;Funcin para procesamiento del nmero decimal
;;;Recibe como argumento el predicado a aplicar
;;;segn sea el argumento numrico positivo o
negativo
;;;

(defun ConvierteBinario (numdec predicado / posicion


numbin)
(while (not (minusp (bit (1- (PosBit)))))
(setq numbin
(cons
(if
(apply
predicado
(list (logand (bit posicion) (fix
numdec)) 0)
) ;_ fin de apply
1
0
) ;_ fin de if
numbin
) ;_ fin de cons
) ;_ fin de setq
) ;_ fin de while
) ;_ fin de defun
;;;
;;;Funcin principal
;;;Tiene en cuenta si se trata de un nmero positivo
o negativo:
;;;
(defun Binario (numdec /)
(if (minusp numdec)
(ConvierteBinario (~ numdec) '=)
(ConvierteBinario numdec '/=)
) ;_ fin de if
) ;_ fin de defun
A diferencia de la funcin BASE, se obtiene una respuesta
correcta tanto de enteros positivos como negativos:

Si deseramos el resultado en formato cadena en lugar de


lista, bastara mapear 'ITOA a la lista devuelta para convertir
los enteros en cadena y aplicarle despus 'STRCAT para unir
los caracteres en una cadena nica:

Dedicaremos la prxima seccin a la conversin en el otro


sentido, de binario a decimal.
CONVERSIN ENTRE BINARIOS Y DECIMALES (II)

CONVERSIN BINARIO->DECIMAL

Esta funcin, complementaria de la anterior, nos permite


hacer la conversin en sentido inverso, partiendo de un valor
binario y convirtindolo en decimal.
Aunque lo ms probable es que el tipo de entrada del dato
sea numrico, hemos diseado una funcin como filtro de
entrada que analizar mediante un COND las posibles
entradas admitiendo listas y cadenas y rechazando cualquier
otro tipo de dato.
en caso de que el dato no sea de uno de estos tres tipos
admitidos, se imprimir un mensaje de error. Si el dato es
admitido pero no es de carcter binario (incluye trminos
distintos de cero uno, la funcin devolver NIL.
;;;DECIMAL.LSP
;;;Recibe un nmero binario y lo convierte en
decimal
;;;debe comprobar el tipo de dato recibido,
;;;que puede ser cadena, nmero o lista
;;;
;;;Funcin utilitaria BIT
;;;devuelve el valor decimal del bit en la posicin
recibida:
;;;
(defun Bit (pos) (lsh 1 (1- pos)))

;;;
;;;
;;;Funcin utilizada como acumulador del valor de la
posicin:
;;;
(defun PosBit ()
(if (null posicion)
(setq posicion 1)
(setq posicion (1+ posicion))
) ;_ fin de if
) ;_ fin de defun
;;;
;;;PREDICADOS DEFINIDOS PARA ESTA FUNCIN:
;;;Como filtro de entrada se emplean tres predicados
;;;definidos expresamente para ella:
;;;STRINGP, STD-DOTTED-PAIR-P y BINARIOP
;;;
;;;Predicado STRINGP
;;;Comprueba si el dato es una cadena
;;;(ver PREDICADOS DEFINIDOS POR EL USUARIO)
;;;
(defun stringp (dato) (equal (type dato) 'STR))
;;;
;;;Predicado STD-DOTTED-PAIR-P
;;;Comprueba de que se trate de un par punteado:
;;;Adaptado de la Standard Lisp Library
;;;de Reini Urban:
;;;
(defun STD-DOTTED-PAIR-P (lst)
(and (vl-consp lst) (not (listp (cdr lst))))
) ;_ fin de defun
;;;
;;;Predicado Binariop
;;;Comprueba que la lista incluya valores slo 0 1
;;;
(defun Binariop (numbin /)
(apply 'and
(mapcar '(lambda (term) (or (equal term 0)
(equal term 1)))
numbin
) ;_ fin de mapcar
) ;_ fin de apply
) ;_ fin de defun
;;;
;;;Funcin utilitaria NUMLISTA

;;;Recibe cualquier nmero decimal y devuelve los


dgitos aislados
;;;en formato de lista
;;;Si el nmero es real, lo trunca despreciando los
decimales
;;;
(defun Numero->Lista (numero / lista)
(while (> numero 0)
(setq lista (cons (rem (fix numero) 10) lista))
(setq numero (/ (fix numero) 10))
) ;_ fin de while
lista
) ;_ fin de defun
;;;
;;;Funcin utilitaria Cadena->Lista
;;;Recibe una cadena de caracteres y devuelve los
caracteres
;;;aislados en formato de lista
;;;
(defun Cadena->Lista (cadena)
(mapcar
'chr
;3.- convierte los
cdigos ASCII a caracteres
(vl-string->list
;2.- convierte la
cadena a lista de cdigos ASCII
cadena
) ;_ fin de vl-string->list
) ;_ fin de mapcar
) ;_ fin de defun
;;;
;;;Funcin ConvierteDecimal
;;;Realiza la conversin, al ser la evaluacin
siempre de izquierda a derecha,
;;;debe invertir la lista para iniciar la
comprobacin por el bit ltimo de la derecha.
;;;Esta comprobacin se hace mediante el mapeado de
una funcin LAMBDA a la lista,
;;;que comprueba si el nmero es cero y en caso que
no lo sea, inserta el valor
;;;decimal del bit en la lista
;;;Una vez concluido este mapeado, se le aplica la
funcim '+ para sumar todos
;;;los valores, con lo que obtenemos el resultado de
la conversin Binario->Decimal.
;;;Devuelve un nmero decimal

;;;
(defun ConvierteDecimal
(numbin / posicion)
(if (Binariop numbin)
(apply
'+
;
suma los valores
de la lista devuelta por MAPCAR
(mapcar
(function
(lambda (x)
(PosBit)
;5.- valora la
variable posicion
(if
(not (zerop x))
(bit posicion)
0
;
en caso
contrario devuelve cero
) ;_ fin de if
) ;_ fin de lambda
7.- y los
valores devueltos quedan en una lista
) ;_ fin de function
(reverse numbin)
) ;_ fin de mapcar
) ;_ fin de apply
nil
) ;_ fin de if
) ;_ fin de defun
;;;
;;;Funcin filtro de entrada, considerando los
posibles tipos de entrada:
;;;Lista, cadena o nmero
;;;los nicos trminos aceptados sern en cualquier
caso ceros o unos
;;;de detectarse otro valor, la funcin devuelve NIL
;;;Otro error derivara de que la lista fuera un par
punteado
;;;Para comprobarlo utilizaramos la funcin STDDOTTED-PAIR-P adaptada de
;;;la Standard LISP library de Reini Urban
;;;
(defun Decimal (numbin /)
(cond
((STD-DOTTED-PAIR-P numbin)
(terpri)
(princ numbin)
(princ " no es un valor admitido.")
(princ)

)
((listp numbin)
;;si es lista, convierte los trminos
(setq
numbin ;;que sean cadenas en nmeros (o
tomos simblicos si fueran letras)
(mapcar
(function (lambda (term)
(if
(stringp term)
(read term)
term
) ;_ fin de if
) ;_ fin de lambda
) ;_ fin de function
numbin
) ;_ fin de mapcar
) ;_ fin de setq
(ConvierteDecimal numbin)
)
((numberp numbin)
;;si es nmero lo convierte en cadena para
despus hacerlo lista
(setq numbin (Numero->Lista numbin))
(ConvierteDecimal numbin)
)
((stringp numbin)
(setq numbin (mapcar 'read (Cadena->Lista
numbin)))
(ConvierteDecimal numbin)
)
(t
(terpri)
(princ numbin)
(princ " no es un valor admitido.")
(princ)
)
) ;_ fin de cond
) ;_ fin de defun
A continuacin algunos ejemplos tomados de la consola de
VISUAL Lisp:

A continuacin analizaremos la funcin LOGIOR.


LOGIOR

Ms arriba plantebamos que para activar un BIT


determinando mediante la suma del valor decimal que
devuelve nuestra funcin (bit posicin) era necesario verificar
que ese BIT no estuviera ya activo. Esto lo podemos lograr
con la funcin LOGIOR. Tambin para LOGIOR recurriremos a
Jon Fleming * en su aporte a la mencionada discusin en
autodesk.autocad.customization:
(LOGIOR ...) trabaja exactamente de la misma manera,
excepto de que escribimos un 1 en la posicin donde uno de
los valores o ambos valores de los argumentos que se le
pasan tienen un 1, y ponemos un 0 donde ambos argumentos
deben tener un 0. Esto es til para combinar nmeros.
Quiere asegurarse de que la referencia a objeto
INTERSECCIN est activa sin afectar a otros modos de
referencia que se hubieren establecido previamente?
(setvar "OSMODE" (logior 32 (getvar "OSMODE")))

Por supuesto, tanto (logand ...) como (logior ...)


pueden aceptar ms de dos argumentos. En este caso:
1. Se aplica la funcin a los dos primeros argumentos,
obteniendo un resultado provisional.
2. Se aplica la funcin al resultado provisional y al
tercer argumento, obteniendo un nuevo resultado
provisional.
3. Se repite el proceso de aplicar la funcin al
resultado provisional actual y al siguiente
argumento hasta agotar los argumentos pasados a
la funcin.
ALGUNOS EJEMPLOS:

De Tony Tanzillo <tony.tanzillo@worldnet.att.net>


tomamos los siguientes ejemplos del uso de estas funciones:
Determinar si un bloque es una Referencia Externa
(RefX):
Esta funcin toma la lista de asociacin devuelta por
(tblsearch/siguiente), y devuelve T si el bloque es una
referencia externa:
(defun isXref (data)
(eq 4 (logand 4 (cdr (assoc 70 data))))
)
Comprobar el valor de la variable CMDACTIVE:
No debemos utilizar la funcin = para comprobar el valor de
CMDACTIVE, ya que su valor puede variar (y de hecho asumir
valores no documentados y totalmente inesperados). En lugar
de
(= 1 (getvar "cmdactive")),
se debe utilizar:
(eq 1 (logand 1 (getvar "cmdactive")))
Desactivar REFENT:

Para dejar sin efecto mediante LISP las referencias a objeto


de carcter permanente (establecidas mediante REFENT) sin
cambiar los valores preestablecidos (lo que equivaldra a
pulsar la tecla F3), se puede activar el noveno bit (valor
decimal de 16384):
(setvar "OSMODE" (logior (getvar "osmode") 16384))
o utilizando la funcin BIT antes definida:
(setvar "OSMODE" (logior (getvar "osmode")(bit 9)))
Otros ejemplos los podemos obtener de los mismos
programas LISP que acompaan a AutoCAD. Para el uso de
LOGIOR puede consultarse DDOSNAP.LSP de la versin 13,
AI_UTILS.LSP, DDCHPROP.LSP, DDMODIFY.LSP y
DDSELECT.LSP, de las versiones 13 y 14 y EXCHPROP.LSP
y MPEDIT.LSP, estos ltimos de la versin 14.
* De: Jon Fleming < jonf@fleming-group.com>
Newsgroup: autodesk.autocad.customization
Asunto: Logand, logior, lsh, etc...
Fecha: Jueves, 26 Feb 1998 20:35:37 EST
Organizacin: The Fleming Group
Traduccin del ingls: Reinaldo Togores

BOOLE

BOOLE opera como una funcin lgica binaria de carcter


general, con lo que incluira las estudiadas LOGAND y LOGIOR
y otras hasta completar las 16 posibles. su sintaxis es:
(Boole operador entero1 [entero2 ...])
El argumento operador es un entero que representa un
nmero binario de 4 bits. cada bit establecido representa una
opcin segn la tabla siguiente:
Bit

Entero1 Entero2 Resultado:

_$
(boole 1
1 1)
1

_$
(boole 2
1 0)
1

_$
(boole 4
0 1)
1

_$
(boole 8
0 0)
-1

Cda bit de entero1 es comparado con el correspondiente bit de


entero2, especificando una fila de la table de resultados anterior.
El bit resultante ser 0 1 segn est activado el bit del
nmero entero que damos como operador que corresponde a
esta posicin. Si el bit en cuestin est activado el bit
resultante es 1; de no ser as el resultado ser 0.
Para ciertos valores del operador, BOOLE equivale a las
operaciones Booleanas standard de AND, OR, XOR, y NOR.
Operador
Binario

Operacin
Booleana

AND

6 (4 + 2)

XOR

7 (4 + 2 +
1)

OR

NOR

Resultado igual a 1 si de los


bits analizados:

Ambos son 1
Slo uno de ellos es
igual a 1
Cualquiera de ellos es
1
Ambos son 0
(complemento de 1)

Para tratar de comprender mejor lo anterior analizaremos un


ejemplo tomado de la ayuda de Visual LISP:
(boole 6 6 5) devuelve 3

Aprovechando las funciones antes definidas hallaremos el


equivalente binario de 6, que sera (despreciando los ceros a
la izquierda) igual a 110.
Lo mismo para 5 devolvera 101.
ahira podemos hacer la comparacin para cada pareja de
bits:
Primera pareja: (boole 6 0 1) devuelve 1
Segunda pareja (boole 6 1 0) devuelve 1
Tercera pareja: (boole 6 1 1) devuelve 0
Con lo que tendramos el nmero binario 011, que como
podemos comprobar aplicando la funcin DECIMAL equivale a
3. Todo esto visto desde la consola de Visual LISP sera:

Normalmente sera ms cmodo emplear LOGAND y LOGIOR


cuando fuera posible reservando BOOLE para otras
operaciones lgicas binarias. Si revisamos los programas LISP
incluidos con la aplicacin AutoCAD encontraremos al gunos
ejemplos del uso de esta funcin. Para ello podemos consultar
los archivos DDMODIFY.LSP, MPEDIT.LSP, BURST.LSP y
ASESMP.LSP de la versin 14, y PROJECT.LSP y FACE.LSP
de la Versin 12.
PREDICADOS GENERALES DEFINIDOS POR EL USUARIO

La posibilidad de desarrollar funcuiones de carcter utilitario


nos permiten completar los predicados de Visual Lisp con
otros de uso probable dentro de las utilidades que se
desarrollen dentro de Autocad.
Predicados para comprobacin de tipo de objeto:

Tipos de Datos LISP:

INTEGERP
Comprueba si el argumento es un nmero entero.
(defun integerp (dato)(eq (type dato) 'INT))
REALP
Comprueba si el argumento es un nmero real.
(defun realp (dato)(eq (type dato) 'REAL))
STRINGP
Comprueba si el argumento es una cadena.
(defun stringp (dato)(eq (type dato) 'STR))
Tipos de Datos AutoCAD:

ENAMEP
Comprueba si el argumento es un nombre de entidad.
(defun enamep (dato)(eq (type dato) 'ENAME))
FILEP
Comprueba si el argumento es un identificador de archivo.
(defun filep (dato)(eq (type dato) 'FILE))
PAGETBP
Comprueba si el argumento es una Tablas de Paginacin de
Funciones.
(defun pagetbp (dato)(eq (type dato) 'PAGETB))
PICKSETP
Comprueba si el argumento es un Conjunto de Seleccin.
(defun picksetp (dato)(eq (type dato) 'PICKSET))

SUBRP
Comprueba si el argumento es una Funcin AutoLISP interna
o compilada.
(defun subrp (dato)(eq (type dato) 'SUBR))
USUBRP
Comprueba si el argumento es una funcin de usuario
cargada desde un fichero fuente LSP.
(defun usubrp (dato)(eq (type dato) 'USUBR))
EXRXSUBRP
Comprueba si el argumento es una Aplicacin ObjectARX
Externa.
(defun exrxsubrp (dato)(eq (type dato) 'EXRXSUBR))
Tipos de Datos ActiveX

SAFEARRAYP
Comprueba si el argumento es una Matriz del tipo Safearray.
(defun safearrayp (dato)(eq (type dato) 'SAFEARRAY))
VARIANTP
Comprueba si el argumento es del tipo Variant.
(defun variantp (dato)(eq (type dato) 'VARIANT))
VLA-OBJECT-P
Comprueba si el argumento es un Objeto ActiveX.
(defun vla-object-p (dato)(eq (type dato) 'VLAobject))

ESTRUCTURAS CONDICIONALES

CONDICIONAL IF

ESTRUCTURA IF-THEN-ELSE
Evala expresiones condicionalmente:

(if expr_prueba expr_then [expr_else])


Si expr_prueba no es nil, evala expr_then;
en caso contrario evala expr_else.
La funcin if devuelve el valor de la expresin
seleccionada. Si expr_else no existe y expr_prueba es
nil, entonces la funcin if devuelve nil.
Funcin PROGN
Calcula las expresiones secuencialmente y devuelve el
valor de la ltima expresin
(progn [expr]...)
Se suele utilizar progn para calcular varias expresiones
cuando slo se espera, como en cada una de las ramas
del IF, una sola expresin.
CONDICIONALES DE USO GENERAL

En muchos casos nos encontraremos que hay ms de dos


condiciones sobre las que decidir. En estos casos podemos
acudir a la funcin COND, que evala una serie de
condiciones de prueba secuencialmente.
COND
Se utiliza como la funcin condicional primaria de Visual
LISP
(cond (prueba1 resultado1 ...) ...)
La funcin cond acepta cualquier nmero de listas como
argumentos.
Evala el primer elemento de cada lista (en el orden indicado)
hasta que uno de ellos devuelva un valor distinto de nil. A
continuacin, evala las expresiones que siguen a este
elemento y devuelve el valor de la ltima expresin de la
sublista. Si esta sublista slo contiene un valor (es decir, si
falta resultado), se obtiene el valor de la expresin prueba.
COND se puede utilizar como una funcin de tipo case.
Es habitual utilizar T como ltima (por defecto) expresin de
prueba.

FUNCIONES RECURSIVAS E ITERATIVAS

Muchos de las tareas que tratamos de resolver con


ordenadores implican la ejecucin de procedimientos en
forma repetitiva. LISP suministra dos paradigmas para el
control de las tareas repetitivas: la recursin y la iteracin.
La definicin de nuevas funciones consiste bsicamente en la
combinacin de llamadas a otras funcin que resulten
adecuadas a los fines que nos proponemos. Un caso particular
surge cuando la funcin se llama a s misma. Estas funciones
suelen llamarse funciones recursivas. Obsrvese que la
funcin recursiva se repite invocndose a s misma. Esto lo
hace desde la llamada inicial al programa. As que para cada
repeticin hay una nueva llamada a la funcin original.
Cualquier otro procedimiento repetitivo que no implique una
recursin es un procedimiento iterativo. Visual LISP
suministra una serie de funciones especficas para la
implementacin de procedimientos iterativos. Las formas ms
simples de establecer una iteracin seran las funcin REPEAT
y FOREACH para listas y VLAX-FOR para colecciones de
objetos ActiveX (VLA-object). REPEAT realiza los
procedimientos especificados el nmero de veces que se
especifique en su primer argumento que debe ser un nmero
entero positivo. FOREACH suministra una iteracin de manera
directa sobre los elementos de una lista. FOREACH debe
recibir como segundo argumento una forma que evale como
lista. Entonces ejecuta el cuerpo de instrucciones
suministrado como sucesivos argumentos una vez para cada
uno de los elementos de la lista. Cuando la conclusin del
ciclo de repeticiones dependa de que se alcance determinado
estado y no sea posible predeterminar el nmero de
iteraciones que ello exigir podemos utilizar la funcin WHILE
que admite como primer argumento una funcin predicado
cuyo no cumplimiento (evaluacin como NIL) determinar la
salida del bucle iterativo.
Existen tambin las llamadas funciones de mapeado. El
Mapeado es un tipo de iteracin en la cual una funcin se
aplica sucesivamente a elementos de una o ms secuencias
de objetos. El resultado de la iteracin es una secuencia que
contiene los resultados de las aplicaciones de la funcin.

Visual LISP provee dos funciones de mapeado: MAPCAR, para


listas y VLAX-MAP-COLLECTION para colecciones de objetos
ActiveX.

FUNCIONES RECURSIVAS

El ejemplo clsico de una funcin recursiva es el clculo del


factorial de un nmero. Por ejemplo, 4! (factorial) es igual a 4
X 3 X 2 X 1. Algebraicamente, podemos considerar un
factorial como (n!) as n X (n-1) X (n-2) X (n-3)...(n - (n+1)).
sta sera la definicin recursiva del factorial:
(defun factorial (n)
(cond
((zerop n) 1)
(T
(* n (factorial (1- n))))
) ;_ fin de cond
) ;_ fin de defun
Se analizan dos condiciones:
1. que el argumento recibido sea cero (predicado ZEROP).
En ese caso se devuelve 1.
2. en cualquier otro caso, se multiplica el argumento por el
resultado que devuelve aplicar de nuevo la funcin de
usuario factorial al argumento menos 1. Lgicamente
la evaluacin de esta operacin deber esperar al
resultado de la nueva llamada a la funcin factorial,
que si an no es cero, provocar una nueva llamada a la
misma funcin factorial y quedar a la espera de que
esta sea evaluada y as sucesivamente. Al llegar a cero
el argumento pasado a factorial, ya no se producir
una nueva llamada a la funcin y se comenzar a
devolver respuestas a todas la evaluaciones que han
quedado pendientes. Este comportamiento puede verse
claramente en la ventana TRACE de visua LISP, despus
de haber evaluado la funcin (trace factorial) .

La recursin, aunque aporta soluciones de gran elegancia,


debe ser utilizada con cautela. Lo ideal sera usarla con
funciones que no utilicen, o utilicen muy pocos argumentos,
ya que la recursin coloca cada vez una nueva copia de la
funcin en la memoria de pila junto con sus argumentos. Es
muy posible que una funcin efecte tantas recursiones que
se agote la memoria disponible provocando un error de
desbordamiento de la pila.
Para ms detalles, consultar el artculo WHAT IS
RECURSION? de Glenn Grotzinger.
ANLISIS DE UNA FUNCIN RECURSIVA

La siguiente funcin demuestra la posibilidad de desarrollar


funciones de usuario a partir de un corto nmero de
primitivas. La funcin BUSCA_EN_LISTA recibe como
argumentos una expresin cualquiera y una lista. En caso que
la expresin est contenida en la lista, la funcin devolver la
expresin y todos los trminos de la lista que ocurren
despus de la expresin. Si expresin no pertenece a la lista,
la funcin devuelve nil. Los resultados obtenidos son los
mismos que los de la funcin primitiva MEMBER. De hecho
muchas de las funciones hoy incorporadas a cualquiera de los
dialectos modernos de LISP surgieron como funciones
utilitarias que eran incorporadas de manera habitual por los
usuarios.
;;;Funcin recursiva busca_en_lista.
;;;Equivale a la funcin member de LISP
;;;Esta funcin ha sido adaptada del tutorial
;;;LISP del ELM Research Group
(defun busca_en_lista (expresion lista)
(cond

((null lista) nil)


;si
lista est vaca o se acaba
((equal expresion (car lista)) lista)
;si
se encuentra expresion
(t (busca_en_lista expresion (cdr lista))) ;en
otro caso se efcta la recursin
)
)
_$ (busca_en_lista '(a b) (list 2 r "sdf" '(a b)
"KLM" 77 21 jfk))
((A B) "KLM" 77 21 nil)
_$ (member '(a b) (list 2 r "sdf" '(a b) "KLM" 77 21
jfk))
((A B) "KLM" 77 21 nil)
_$
Si antes de ejecutar esta funcin invocamos la funcin
TRACE:
(trace busca_en_lista)
podemos seguir en la ventana TRACE de Visual LISP los pasos
seguidos en la evaluacin de esta funcin:
Entering (BUSCA_EN_LISTA (A B) (2 nil "sdf" (A B)
"KLM" 77 21 nil))
Entering (BUSCA_EN_LISTA (A B) (nil "sdf" (A B)
"KLM" 77 21 nil))
Entering (BUSCA_EN_LISTA (A B) ("sdf" (A B)
"KLM" 77 21 nil))
Entering (BUSCA_EN_LISTA (A B) ((A B) "KLM" 77
21 nil))
Result: ((A B) "KLM" 77 21 nil)
Result: ((A B) "KLM" 77 21 nil)
Result: ((A B) "KLM" 77 21 nil)
Result: ((A B) "KLM" 77 21 nil)
Los objetivos perseguidos implican el recorrido de la lista,
elemento a elemento, comparando cada uno con la expresin
dada. La manera ms sencilla para extraer un elemento de la
lista (el primero) es utilizar la funcin CAR. Un segundo
elemento pudiera extraerse con CADR y as sucesivamente.
Pero este mtodo sera demasiado rgido si queremos que la
funcin sea aplicable a una lista de cualquier longitud.

Una solucin estara en que si el primer elemento no es el


buscado, volviramos a ejecutar la funcin pero que esta vez
el segundo argumento (lista) fuera el resto de la lista,
quitando el primer trmino ya analizado: (cdr lista).
As continuaramos probando el primer trmino (CAR de la
lista) del resto (CDR) de la lista hasta que o termine la lista o
que el primer trmino sea el elemento buscado.
Las condiciones que se prueban corresponden a los tres casos
posibles al suministrar a la funcin BUSCA_EN_LISTA dos
argumentos, el primero de los cuales puede ser un tomo o
una lista y el segundo debe evaluar como una lista, incluso
vaca.
Primer caso: ((null lista) nil)
Cuando se encuentra esta condicin, la evaluacin
termina. La funcin evaluar en este caso como nil,
sealando que el trmino no ha sido encontrado. Este
sera tambin el caso si el segundo argumento fuera una
lista vaca.
Segundo caso: ((equal expresion (car lista)) lista)
Al igual que en el primer caso, la evaluacin termina.
Pero en este caso el primer trmino de la lista (car lista)
es el trmino buscado, y se devuelve el valor de lista.
Tercer caso: (t (busca_en_lista expresion (cdr lista)))
Este es el caso en que se produce la recursin. Siempre
que lista no est vaca (null lista) y que el primer
elemento de lista no sea igual al trmino buscado, se
llama de nuevo a la funcin BUSCA_EN_LISTA pero esta
vez se le pasa como argumento lista (cdr lista), el resto
de la lista, desechando el primer trmino. As a cada
ciclo, lista se acorta en un trmino. Al final, si expresion
no formara parte de lista, la recursin terminara al
llegar a ser una lista nula.
Si observamos lo devuelto en la ventana TRACE por una y
otra de estas dos funciones recursivas, observamos una
diferencia. Lo devuelto por el ltimo nivel de recursin en la
funcin FACTORIAL es diferente a lo devuelto por el nivel
superior. De hecho cada nivel devuelve un resultado diferente.

Para llegar al resultado definitivo, debemos esperar a lo que


devuelve cada uno de los ciclos de la recursin. Sin embargo,
en la segunda funcin BUSCA_EN_LISTA, el resultado del
ltimo nivel es ya el resultado definitivo. Es evidente que
resulta una prdida de tiempo el esperar a que cada nivel
devuelva ese mismo resultado hasta llegar al nivel superior.
Los compiladores LISP ms avanzados reconocern una
funcin de este tipo y cortarn el proceso en el instante que
se obtiene el resultado del ltimo nivel, mejorando
sustancialmente la velocidad de operacin de las funciones.
Este tipo de funciones recursivas se conocen por el trmino
ingls de TAIL-RECURSIVE (~ recursivas por la cola).
En muchos casos, hacer una funcin recursiva por la cola
(tail-recursive) es posible empleando tcnicas adecuadas de
programacin. Siempre que esto se logre podemos esperar un
incremento significativo en la eficacia de los programas.
Nota: Segn afirma Reini Urban, VLISP no es capaz de
reconocer la recursividad por la cola o tail-recursion, de
manera que an resulta en una utilizacin exhaustiva de la
memoria de pila (stack). Sobre los lmites valores mximos
admitidos de anidacin (tamao de pila) dicho autor propone
ejemplos en http://xarch.tugraz.ac.at/autocad/stdlib/STDINIT2.LSP
SU UTILIZACIN PRCTICA DENTRO DE AUTOCAD

Como ejemplo de la utilidad de los mtodos de programacin


expuestos, desarrollaremos un programa encaminado a
resolver un problema concreto dentro de la aplicacin. En
ocasiones tenemos la necesidad de extraer la informacin de
las coordenadas de los vrtices de una polilnea. En este caso
analizaremos una polilnea del tipo LWPOLYLINE, que se
introdujo con la versin 14 de AutoCAD. Las entidades de
AutoCAD guardan su informacin en forma de listas de
asociacin, una lista con sublistas donde el nmero inicial de
cada sublista identifica el tipo de dato de que se trata. Un
proceso recursivo sera especialmente adecuado para recorrer
dicha lista extrayendo de ella la informacin requerida.
Pasaremos entonces a estudiar el desarrollo de una
FUNCIN RECURSIVA PARA LA LECTURA DE LOS
VRTICES DE UNA POLILNEA

Extraccin de los vrtices de una LWPOLYLINE

Los datos que sirven para definir cada una de los objetos
grficos de AutoCAD estn organizados en forma de una lista
de asociacin, es decir, una lista de listas, donde la
informacin guardada en cada sublista se identifica mediante
un cdigo numrico (entero) que aparece como el primer
trmino (CAR) cada sublista. El significado de cada cdigo
coincide en trminos generales con los cdigos que identifican
los datos contenidos en los archivos del formato de fichero
DXF utilizado para la transferencia de dibujos AutoCAD a
otras aplicaciones. Para el desarrollo de la siguiente funcin
basta saber que los valores que corresponden a las
coordenadas X e Y de cada vrtice aparecen en sucesivas
sublistas identificadas mediante el cdigo de asociacin 10. La
coordenada Z aparece en una nica sublista (ya que debe ser
la misma para todos los vrtices) identificada mediante el
cdigo 38. La funcin recursiva descrita a continuacin ser
llamada desde otra funcin que permita seleccionar un objeto
del dibujo, compruebe a continuacin que se trata de la
entidad deseada (del tipo "LWPOLYLINE"), extraiga del objeto
grfico seleccionado la correspondiente lista de asociacin y la
pase, junto con el valor de la elevacin, como argumentos a
la funcin recursiva de extraccin VertPoly.
Funcin ExtraeVertices:

Existen varias formas para seleccionar objetos del dibujo.


Utilizaremos en este caso la funcin ENTSEL que pide al
usuario designar un objeto en el dibujo y devuelve una lista
con el nombre de entidad y la lista de coordenadas XYZ del
punto que ocupaba el cursor en el momento de hacer la
designacin. Este segundo dato no nos es necesario, por lo
que anidamos la funcin ENTSEL dentro de una funcin CAR.
El nombre de entidad que obtenemos de esta manera es en
realidad un puntero al archivo temporal que crea AutoCAD al
abrir un dibujo. Utilizando dicho puntero podemos localizar la
definicin interna del objeto grfico designado en pantalla y
extraerla mediante la funcin ENTGET:
(entget (car (entsel)))

Una sublista determinada se puede encontrar mediante la


funcin ASSOC, pero en este caso, las sublistas que guardan
las coordenadas de los vrtices todas poseen el cdigo 10.
Por este motivo, ser necesario recorrer toda la lista, trmino
a trmino para encontrar todos los valores de coordenadas
correspondientes a los vrtices. Estos valores son slo de las
coordenadas X e Y. La Z se encuentra en una lista asociada al
cdigo 38. Habr que extraer este valor inicialmente y luego
agregarlo a cada uno de los vrtices. Esto se har utilizando
la funcin APPEND en lugar de CONS, de manera que se
aada el valor de Z en la tercera posicin y no al principio de
la lista. La funcin devolver una lista de listas, estas ltimas
cada una de tres valores, correspondiendo a la X,Y,Z de cada
vrtice.
;;;Extraccin de los vrtices de una LWPOLYLINE
;;;Funcin recursiva:
;;;Recorre la lista y extrae el valor de los cdigos
10
;;;Estas listas de asociacin slo incluyen los
valores
;;;de las coordenadas X e Y, el valor de Z para toda
la
;;;polilnea est asociado al cdigo 38 este valor
as
;;;como la lista de entidad se extraen en una
funcin
;;;inicial que adems sirve para declarar como
variables
;;;locales las que almacenan la lista definitoria de
la
;;;entidad y la lista de vrtices.
;;;Esta funcin devuelve la lista de vrtices, que
se
;;;puede asignar a una variable mediante setq:
;;;
(setq vertlis (ExtraeVertices))
;;;(c) Reinaldo Togores, Santander, Julio 1999.
(defun VertPoly (lista elevacion / )
(cond
((null lista) nil)
;funcin
de salida
((equal (caar lista) 10)
;si se
trata de un vrtice

(cons
;la
funcin append permite incluir la
(append (cdr (car lista))(list
elevacion)) ;coordenada Z en la posicin correcta
(VertPoly (cdr lista) elevacion)
;y
contina la recursin
)
)
(t (VertPoly (cdr lista) elevacion))
;si no
es un vrtice
) ;_ fin de cond
) ;_ fin de defun
(defun ExtraeVertices ( / lista_entidad)
(if
(equal
(cdr (assoc 0 (setq lista_entidad (entget (car
(entsel))))))
"LWPOLYLINE"
)
(VertPoly lista_entidad (cdr (assoc 38
lista_entidad)))
(alert "La entidad seleccionada no es una
LWPOLYLINE")
) ;_ fin de if
) ;_ fin de defun
Sin duda este cdigo cumplir su cometido, pero puede ser
mejorado. Este programa est redactado de manera tal que
ninguna de sus partes pudiera reutilizarse en otros futuros
programas. Un enfoque ms eficaz consistira en analizar qu
procesos de carcter ms general intervienen en la solucin y
programarlos como funciones utilitarias que se incorporen
como nuevas herramientas al lenguaje. Ms adelante, y
despus de estudiar algunos otros procedimientos y tcnicas,
intentaremos precisamente esto, cmo abordar de una
manera ms eficaz la solucin a este programa.

FUNCIONES ITERATIVAS

ITERACIONES SIMPLES

En algunos casos puede ser conveniente otro enfoque de las


operaciones repetitivas, mediante estructuras en bucle que no
implican procedimientos de auto-referencia. Los operadores
REPEAT y FOREACH ejecutan las expresiones dadas un nmero
defterminado de veces. En el primer caso se trata del nmero
de veces que resulta de la evaluacin del primero de sus
argumentos y en el segundo de la cantidad de elementos que
pertenecen a una lista. Esta ltima funcin tiene en Visual
LISP su equivalente aplicable a objetos de coleccin ActiveX
bajo el nombre de VLAX-FOR
Tanto para REPEAT como para FOREACH se puede establecer
de antemano el nmero de ciclos a realizar. Pero esa no es
siempre la situacin. En muchas ocasiones no hay manera de
saberlo. En estos casos se deber establecer, al igual que en
los procedimientos recursivos una condicin de prueba que
determine la conclusin del ciclo. Para ello disponemos de la
funcin WHILE.
REPETICIN UN NMERO DETERMINADO DE VECES

REPEAT
Evala cada expresin el nmero de veces que se
especifique en el argumento entero, y devuelve el valor
de la ltima expresin
(repeat entero expresin ...)
El argumento entero debe ser un nmero entero
positivo.
Ejemplos de iteraciones con REPEAT:

FACTORIAL ITERATIVO
Como primer ejemplo analizaremos la funcin FACT2
propuesta por Dennis Shinn <jeeper@halcyon.com>
en el newsgroup comp.cad.autocaden septiembre de
1996. La explicacin es nuestra traduccin libre del
original.
(defun fact2 (n / x y)
(setq x 1 y 1)
(repeat (1- n)

(setq

x (1+ x) y (* x y) )

)
)
En la primera lnea se asigna el valor inicial correcto a
las dos variable que llamamos x e y.
La repeticin se establece para un nmero especfico de
veces segn el nmero que se pase como argumento a
la funcin. Puesto que la operacin del clculo del
factorial implica la cantidad de nmeros a multiplicar
menos 1, establecemos en (1- n) el nmero de
repeticiones.
Ahora vienen los clculos matemticos: (setq x (1+ x)
y (* x y))
Durante cada iteracin de esta expresin, la x se
incrementa por un valor de 1 cada vez, e y se
incrementa como el producto de ella misma y el prximo
valor mayor de x, etc., etc.
Obsrvese que no se ha implementado un control de
errores, que es algo deseable en un lenguaje de
programacin. Tanto 0 como 1 quedan indefinidos, ya
que ninguno de los dos permitir que ocurra la iteracin.
El REPEAT simplemente no repite. Vale, sin embargo
para demostrar las posibilidades de un verdadero
lenguaje de programacin (como LISP) para realizar
verdaderas operaciones de recursin e iteracin.
Como muestra de una implementacin para atrapar
posibles errores podramos crear otra rutina fact3 que
llame a la rutina fact2 slo en los casos apropiados:
(defun fact3 (n)
(cond
((and (numberp n)(> n 1))
(fact2 n)
)
((= n 1) 1)
(t nil)
)
)

En este caso se prueba primero si el argumento n es un


nmero mayor que 1, en cuyo caso se ejecuta la funcin
fact2. En caso de ser igual a 1 se devuelve 1, y en
cualquier otro caso se devolver NIL.
Predicado PALINDROMOP
El predicado PALINDROMOP debe devolver T (cierto) si
una cadena de texto es un palndromo, es decir, si se lee
lo mismo de izquierda a derecha que al revs. Se ha
utilizado la funcin STRLEN para determinar el nmero
de repeticiones, la funcin SUBSTR para ir extrayendo
caracteres para compararlos, uno a uno, comenzando de
izquierda a derecha y de derecha a izquierda, y la
funcin STRCASE de manera que se ignore la caja
(maysculas o minsculas). Se emplean dos variables
locales, cont y resultado. Esta segunda se establece
inicialmente como T y bastar que no sea igual una de
las parejas de letras analizadas para que adopte el valor
de NIL (falso). Es obvio que bastar con un nmero de
repeticiones igual a la mitad de la longitud de la cadena
de texto, pues ms all de eso se estara comparando
las mismas parejas de caracteres. Al ser ambos
argumentos de la divisin nmeros enteros, el resultado
tambin lo sera, truncando los decimales, por lo que en
una cadena con nmero impar de caracteres no se
comparara el carcter centras consigo mismo.
(defun palindromop (cadena / cont resultado)
(setq
cont 0
resultado t
) ;_ fin de setq
(repeat (/ (strlen cadena) 2)
(if
(not
(equal
(strcase (substr cadena (1+ cont) 1))
(strcase (substr cadena (- (strlen cadena)
cont) 1))
) ;_ fin de equal
) ;_ fin de not

(setq resultado nil)


) ;_ fin de if
(setq cont (1+ cont))
) ;_ fin de repeat
resultado
) ;_ fin de defun
ITERACIONES SOBRE ELEMENTOS DE UNA SECUENCIA

FOREACH
Evala cada expresin para todos los miembros de una
lista
(foreach nombre lista expresin ...)
Recorre la lista, asignando sucesivamente cada elemento
de la lista a la variable nombre y evaluando de esta
manera cada expresin para cada uno de los elementos
de la lista representados por nombre. Puede especificar
tantas expresiones como desee. La funcin FOREACH
devuelve el resultado de la ltima expresin evaluada.
VLAX-FOR
Efecta una iteracin a travs de una coleccin de
objetos evaluando cada expresin
(vlax-for smbolo coleccin [expresin1
[expresin2 ...]])
El argumento smbolo ser asignado a cada Objeto-VLA
de la coleccin. El argumento coleccin representa un
objeto ActiveX del tipo coleccin. [expresin1
[expresin2 ...]] son las expresiones a evaluar. La
funcin devuelve el valor de la ltima expresin
evaluada para el ltimo objeto de la coleccin.
Ejemplos de iteraciones con FOREACH:

Esta pequea subrutina, parte de un programa mayor,


imprime en pantalla en formato de columna la lista que se le
pase como argumento. En el ejemplo se usa para imprimir de
manera ordenada la lista de definicin deuna entidad polilnea
(AutoCAD 2000).
;;;Listado de entidades

;;;Salida por pantalla


(defun disp_l (lis_e /)
(foreach sublista lis_e
(print sublista)
) ;_ fin de foreach
(princ)
;evita la repeticin de la
ltima lnea
) ;_ fin de defun
Command: (entget(car(entsel)))
Select object: ((-1 . <Entity name: 1487558>) (0 .
"LWPOLYLINE") (330 . <Entity
name: 14874f8>) (5 . "2B") (100 . "AcDbEntity")
(67 . 0) (410 . "Model") (8 .
"0") (100 . "AcDbPolyline") (90 . 4) (70 . 0) (43 .
0.0) (38 . 0.0) (39 . 0.0)
(10 99.3432 134.975) (40 . 0.0) (41 . 0.0) (42 .
0.0) (10 130.202 185.828) (40
. 0.0) (41 . 0.0) (42 . 0.0) (10 202.747 163.648)
(40 . 0.0) (41 . 0.0) (42 .
0.0) (10 269.336 215.041) (40 . 0.0) (41 . 0.0)
(42 . 0.0) (210 0.0 0.0 1.0))
;La lista impresa en pantalla resulta difcil de
leer, al no estar ordenada en columna
Command: (disp_l (entget(car(entsel))))
(-1 . <Entity name: 1487558>)
(0 . "LWPOLYLINE")
(330 . <Entity name: 14874f8>)
(5 . "2B")
(100 . "AcDbEntity")
(67 . 0)
(410 . "Model")
(8 . "0")
(100 . "AcDbPolyline")
(90 . 4)
(70 . 0)
(43 . 0.0)
(38 . 0.0)
(39 . 0.0)
(10 99.3432 134.975)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(10 130.202 185.828)
(40 . 0.0)
(41 . 0.0)

(42 . 0.0)
(10 202.747 163.648)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(10 269.336 215.041)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(210 0.0 0.0 1.0)
Ejemplos de iteraciones con VLAX-FOR:

LISTADO DE CAPAS

Considerado desde el punto de vista de la jerarqua de


objetos ActiveX a la que podemos acceder con Visual LISP,
AutoCAD y sus dibujos consisten en muchos objetos
diferentes tales como tipos de lneas, capas, bloques, etc.
Estos objetos se agrupan en colecciones. Las colecciones de
Bloques (Block), Grupos (Group), Conjuntos de Seleccin
(SelectionSet), EspacioModelo (ModelSpace) y EspacioPapel
(PaperSpace) pueden contener una variedad de objetos
grficos diferentes, tales como lneas, arcos, texto, etc. Todas
las dems colecciones contienen objetos de un slo tipo.
Las colecciones AutoCAD son de base cero, es decir que se
enumeran a partir de cero en sentido ascendente. Algunas
colecciones poseen objetos de manera automtica. Por
ejemplo, la coleccin Layers (capas) simpre contiene un
objeto capa de nombre "0", mientras que otras se encuentran
vacas inicialmente.
Sutphin, J. AutoCAD 2000 VBA Programmers Reference, pg 47.
La rutina que exponemos a continuacin extrae los nombres
de las capas de un dibujo aplicando la funcin VLAX-FOR a la
coleccin "Layers". Para obtener la coleccin "Layers"
tenemos que recorrer la jerarqua de objetos, a partir del
nico objeto accesible pblicamente que es el objeto
"Application" (Aplicacin). La secuencia a seguir es la
siguiente:
1. Obtener el objeto "Aplicacin": (vlax-get-acadobject)

2. Obtener el objeto "Documento Activo" es decir, el dibujo


en que se trabaja: (vla-get-ActiveDocument (vlaxget-acad-object))
En caso de que se vaya a hacer referencia a este objeto
en mltiples ocasiones, sera conveniente extraerlo una
sla vez y guardarlo en una variable global:
(setq *EsteDibujo* (vla-get-ActiveDocument
(vlax-get-acad-object)))
Esta lnea la situamos fuera del defun. Se ejecutara al
cargar el programa.
3. Obtener la coleccin "Layers" (Capas): (vlax-get
*EsteDibujo* "Layers" )
Una vez obtenida la coleccin de capas se aplica mediante
VLAX-FOR a cada objeto-VLA de dicha coleccin la funcin
(setq ListaCapas (cons (vlax-get objeto-VLA "Name")
*ListaCapas*))
Aqu primero extraemos el nombre de la capa. El nombre de
cada objeto "Layer" se encuentra en la propiedad "Name" y se
puede extraer mediante (vlax-get objeto-VLA "Name"). Una
vez obtenido el nombre de la capa, la incluimos mediante
CONS en una variable local ListaCapas. Esta lista contendr al
terminar el ciclo de VLAX-FOR los nombres de todas las capas
del dibujo activo. Ya para terminar, ordenamos la lista de
capas mediante la funcin ACAD_STRLSORT. Esta lista
servira, por ejemplo para llenar una casilla de lista en un
cuadro de dilogo creado mediante el lenguaje DCL.
;;;Funcin ListaCapas
;;;Devuelve una lista con los nombres de capas
ordenados alfabticamente
;;;Obsrvese la posibilidad aqu demostrada de tener
una funcin y una variable
;;;con idntico nombre en un mismo entorno. Para
ello ser necesario que dicha
;;;variable, en este caso ListaCapas sea una
variable local de la funcin.
(setq *EsteDibujo* (vla-get-ActiveDocument (vlaxget-acad-object)))
;se ejecuta previamente
(defun ListaCapas (/ ListaCapas)
(vlax-for objeto-VLA (vlax-get *EsteDibujo*
"Layers")

(setq ListaCapas (cons (vlax-get objeto-VLA


"Name") ListaCapas))
;el mismo nombre se utiliza para la variable
local que guarda
;temporalmente el listado de capas.
) ;_ fin de vlax-for
(acad_strlsort ListaCapas)
) ;_ fin de defun
Ejemplo de su utilizacin:
Command: (LOAD "C:/Mis
documentos/Lisp/Fuentes/ListaCapas.lsp") LISTACAPAS
Command: !*EsteDibujo*
<#VLA-OBJECT IAcadDocument 00eb6aa4>
Command: (listaCapas)
("0" "DEFPOINTS" "DOTACIONES" "IT" "RBA" "RE-2" "RI"
"RI-1" "RIA" "SG-EL"
"SG-M" "SGP")
Ms adelante se estudiar en ms detalle el acceso a los
objetos ActiveX desde Visual LISP.
Unos ejemplos para concluir...

Como ejemplo del empleo dentro de AutoCAD de estas


ltimas funciones estudiadas, aqu van algunas pequeas
utilidades creadas por Vladimir Nesterovsky. La primera de
ellas, SEL2LST crea una lista de nombres de entidad a partir
de un conjunto de seleccin. La segunda, LST2SEL, realiza el
proceso inverso, creando un conjunto de seleccin a partir de
una lista de nombres de entidad:
;;;SEL2LST
;;;Recibe un conjunto de seleccin y devuelve una
lista
(defun sel2lst( sel / n l)
(repeat (setq n (sslength sel))
(setq n (1- n) l (cons (ssname ss n) l))
)
)
;;;LST2SEL
;;;La funcin opuesta, recibe una lista y devuelve
un conjunto de seleccin

(defun lst2sel(l / ss)


(setq ss (ssadd))
(foreach e l (ssadd e ss))
)
La siguiente funcin extrae el resto de una lista l a partir del
trmino n indicado en el primer argumento:
(defun cdnr ( n l )
(repeat n
(setq l (cdr l))
)
)
La funcin STRTOL recibe una cadena de caracteres s y
devuelve los caracteres aislados (cadenas de un slo
carcter) agrupados en una lista:
(defun strtol ( s / lst c )
(repeat (setq c (strlen s))
(setq
lst (cons (substr s c 1) lst)
c
(1- c)
)
)
lst
)
Como se ve, esta puede ser otra va para abordar el
desarrollo del predicado PALINDROMOP: obtener mediante
STRTOL la cadena de caracteres en forma de lista y entonces
compararla con la lista invertida por reverse:
(defun palindromop (cadena)
(setq cadena (strtol cadena))
(equal cadena (reverse cadena))
)
;;
;;
;;
;;

Created by Vladimir Nesterovsky


YOU MAY USE THIS FUNCTION AS IT IS FOR ANY PURPOSE
AT YOUR OWN RISK IF YOU RETAIN THIS NOTICE COMPLETE
AND UNALTERED. NO WARRANTIES GIVEN WHATSOEVER.

CICLOS DEPENDIENTES DE UNA CONDICIONAL

Cuando no hay manera de establecer al incio del proceso


iterativo el nmero de repeticiones que sern necesarias se
deber establecer, al igual que en los procedimientos
recursivos una condicin de prueba que determine la
conclusin del ciclo. Para ello disponemos de la funcin WHILE.
WHILE
Evala una expresin de prueba y, si sta no da como
resultado nil, evala otras expresiones para volver de
nuevo a la expresin de prueba
(while expr_prueba expr...)
La funcin while contina hasta que expr_prueba es nil
. Entonces devuelve el valor ms reciente de la ltima
expresin.
Ejemplos de Iteraciones con WHILE:

CONTEO DE ENTIDADES:

Un caso lo tendramos en una funcin que tuviera como


propsito el contar las entidades que forman parte de un
dibujo. Para acceder de manera secuencial a las entidades
que forman parte de un dibujo tenemos la funcin ENTNEXT.
Si establecemos un contador que se incremente por cada
entidad del dibujo tendramos, al llegar a la ltima entidad, el
nmero total de entidades. La funcin concluir en el
momento que la variable ent evale como NIL , es decir,
cuando ENTNEXT ya no devuelva ms ninguna entidad por
haber alcanzado el final de la base da datos del dibujo.
;;;Funcin iterativa para conteo simple
;;;de las entidades en un dibujo
;;;Se establece la variable cont como contador
;;;y la variable ent para guardar el nombre de
;;;cada entidad leda
(defun CuentaEntidades ( / cont ent)
(setq
cont 1
ent (entnext)
;la funcin entnext
sin argumentos
;devuelve la primera
entidad del dibujo
) ;_ fin de setq
(while ent

(setq
cont (1+ cont)
ent (entnext ent) ;devuelve la entidad
que le sigue a ent
) ;_ fin de setq
) ;_ fin de while
cont
;devuelve el valor final
del contador
) ;_ fin de defun
Ms adelante utilizaremos este procedimiento para desarrollar
funciones ms sofisticadas dirigidas a inventariar los objetos
contenidos en un dibujo.
PREDICADO PALINDROMOP OPTIMIZADO:

La versin anterior del predicado PALINDROMOP no resulta muy


eficiente, pues comprueba de manera exhaustiva todos los
caracteres de la cadena, cuando bastara con detectar una
primera desigualdad para decidir que no se trata de un
palndromo. Una solucin ms eficaz debera interrumpir la
evaluacin en ese momento. Eso lo podemos lograr mediante
un ciclo condicional usando WHILE con dos condiciones
encerradas en un AND (que devolver NIL en cuanto una de
ellas deje de ser cierta): que no se hubiera alcanzado el
nmero de repeticiones determinado por (/ (strlen
cadena) 2), y que el valor de resultado sea T. En cuanto se
encuentre una pareja de caracteres desigual resultado pasar
a ser NIL, con lo cual se detendr el ciclo.
(defun palindromop (cadena / cont resultado)
(setq
cont 0
resultado t
) ;_ fin de setq
(while (and (<= cont (/ (strlen cadena) 2))
resultado)
(if
(not
(equal
(substr cadena (1+ cont) 1)
(substr cadena (- (strlen cadena) cont) 1)
) ;_ fin de equal
) ;_ fin de not
(setq resultado nil)

) ;_ fin de if
(setq cont (1+ cont))
) ;_ fin de while
resultado
) ;_ fin de defun
No basta que un programa alcance los resultados deseados.
Debe hacerlo de manera rpida y eficaz. Este es un principio
que no debe olvidarse.

FUNCIONES DE MAPEADO

LISP provee funciones que procesan secuencialmente los


trminos de una lista suministrada como argumento.
MAPCAR
(mapcar funcin lista1 ... listan)
MAPCAR opera sobre los elementos sucesivos de las
listas. Primero se aplica la funcin al CAR de cada lista,
entonces al CADR de cada una y as sucesivamente. Lo
ideal sera que todas las listas fueran de igual longitud.
Si no lo fueran, la iteracin concluye al agotarse la lista
ms corta y los elementos en exceso de las dems listas
se ignoran. MAPCAR devuelve una lista con los resultados
de las sucesivas llamadas a la funcin. Por ejemplo:
_1$ (mapcar 'cons '(a b c) '(1 2 3))
((A . 1) (B . 2) (C . 3))
Una expresin-LAMBDA puede ser utilizada con MAPCAR.
Esto resulta til cuando algunos de los argumentos de
funcin son constantes o se proporcionan mediante
variables u otros mtodos.
Sobre la funcin MAPCAR seguramente no encontraremos una
explicacin ms entusiasta que la de Vladimir Nemerovski a
quien citamos a continuacin:

Ahora trataremos de MAPCAR. Esta es una funcin que


requiere:
1. un smbolo dentro de QUOTE
o una EXPRESIN-LAMBDA (tabin dentro de un
QUOTE )
o una lista de funcin de usuario (igualmente
dentro del QUOTE)
2. alguna lista
3. y otras listas opcionales ms...
Digamos que la invocamos con (mapcar 'mifuncin
milista) El resultado ser una LISTA de los RESULTADOS de
invocar MIFUNCIN con cada elemento de MILISTA. Por
ejemplo, (defun mysqr(x)(* x x)) (mapcar 'mysqr (list
1 2 3 4)) devolvera (1 4 9 16) De nuevo MYSQR aparece
aqu precedida de un apstrofe (QUOTE), ya que MAPCAR
espera que as sea.
MYSQR espera un argumento numrico y eso es lo que
obtiene. Si yo la invocara como (MAPCAR 'MYSQR (list 1 2
"3")) LISP intentara construir una lista de resultados como
[1] (list (mysqr 1) (mysqr 2) (mysqr "3")) y yo
obtendra un error de BAD ARGUMENT TYPE al intentar
procesar el "3". Observe de nuevo que en esta expresin [1],
MYSQR es de nuevo un QUOTED-SYM de una funcin de usuario
previamente definida cuyo resultado evala como una lista,
teniendo tambin una lista como primer argumento, de
manera que en este punto LISP reconoce tal lista como una
funcin de usuario, tratando de evaluarla, sustituyendo los
argumentos ficticios de su lista de parmetros por los
argumentos reales.
De manera que si usted quiere que alguna funcin sea usada
en MAPCAR y no desea que sta permanezca por ah sin ser
utilizada de nuevo, usted puede emplear LAMBDA. Esta funcin
crea un tipo de FUNCIN ANNIMA y la devuelve como
encerrada en QUOTE, tal como lo hara DEFUN (slo que esta
creara una funcin vinculada a un NOMBRE que de esta
manera permanecera formando parte del entorno).

MAPCAR es grandiosa en que no necesita saber cual es la


longitud de una lista de datos. No le importa. Simplemente la
recorre hasta llegar al final, con lo que lo sabr en tiempo de
ejecucin. De manera que usted al escribir la funcin (que en
LISP equivaldra al tiempo de compilacin de lenguajes
compilados como C, etc.), no necesita saber la longitud
exacta de su lista de datos, lo que ES FENOMENAL! Le
permite tratar fcilmente con informacin de longitud
variable, y no olvidemos que toda la informacin real sin duda
lo es.
As que puedo (mapcar 'mysqr '(1 2 3)) o puedo (mapcar
'mysqr '(1 2 3 4 5)), segn haga falta.
Y hay algo ms. Digamos que tengo esta funcin que SUMA
todos sus argumentos. Es un '+, que puedo invocar como:
(+ 1 2) (+ 1 2 3) etc.
Ahora cuando escribo (mapcar '+ '(1 2 3) '(4 5 6)) es
lo mismo que (list (+ 1 4)(+ 2 5)(+ 3 6)) Tambin
puedo escribir (mapcar '+ '(1 2 3)'(4 5 6)'(7 8 9)),
que equivale a (list (+ 1 4 7)(+ 2 5 8)(+ 3 6 9)) etc.
De manera que tenemos algo ms de flexibilidad aqu. Por
supuesto que yo ser el responsable de suministrar a la
funcin invocada con el nmero adecuado de argumentos que
le sern alimentados por MAPCAR, ya que de otra manera
obtendr un error de DEMASIADOS/MUY POCOS ARGUMENTOS
cuando LISP eventualmente la evale.
Fuente:
Subject: A short course in LISP, LAMBDA,
QUOTE, MAPCAR...
Date: Sat, 02 Nov 1996 08:50:38 -0800
From: Lu <learly@ix.netcom.com>
VLAX-MAP-COLLECTION
Aplica una funcin a todos los objetos de una coleccin.
(vlax-map-collection coleccin funcin)
El argumento coleccin representa un Objeto-VLA de
tipo coleccin. El argumento funcin ser un smbolo o
una expresin-LAMBDA que ser aplicada a coleccin.

Ejemplo de utilizacin de

VLAX-MAP-COLLECTION:

Hemos visto anteriormente el desarrolo de una fincin que


devuelve una lista con los nombres de las capas contenidas
en el dibujo utilizando la funcin VLAX-FOR. Una funcin
similar puede desarrollarse con VLAX-MAP-COLLECTION, con
un cdigo resultante aun ms claro y conciso. La funcin que
se pasa a VLAX-MAP-COLLECTION se definir en este caso
como una expresin-LAMBDA. Obsrvese que esta expresin
debe pasarse dentro de un QUOTE.
;;Funcin ListaCapas utilizando VLAX-MAP-COLLECTION
;;;Devuelve una lista con los nombres de capas
ordenados alfabticamente
(setq *EsteDibujo* (vla-get-ActiveDocument (vlaxget-acad-object)))
;se ejecuta previamente
(defun ListaCapas (/ ListaCapas objeto-VLA)
(vlax-map-collection
(vlax-get *EsteDibujo* "Layers")
'(lambda (objeto)
(setq ListaCapas (cons (vlax-get objeto
"Name") ListaCapas))
) ;_ fin de lambda
) ;_ fin de vlax-map-collection
(acad_strlsort ListaCapas)
) ;_ fin de defun
Su utilizacin devuelve idnticos resultado que la anterior
definida con VLAX-FOR.
Unos ejemplos para concluir...
Conversin de cadena a lista:

Conversin de cadena a lista, con MAPCAR, en una sla lnea.


Utilizando esta funcin podemos convertir al instante cadenas
en listas con sus caracteres aislados:
_$ (defun CadenaLista (cadena)(mapcar 'chr (vlstring->list cadena)))
CADENALISTA
_$ (cadenalista "Madrid")
("M" "a" "d" "r" "i" "d")

REMOVE en una sla lnea:

Gracias a Reini Urban hemos podido conocer este brillante


ejemplo desarrollado por Sergei Volkov, implementando la
funcin REMOVE (QUITAR) en una sla lnea:
;;;REMOVE, por Segei Volkov
;;;Recibe una expresin expr y una lista lst.
;;;Devuelve la lista eliminando de ella todas las
ocurrencias de la expresin.
;;;Paso 1: Mediante MAPCAR aplica la funcin LIST a
cada trmino de la lista
;;;
Si recibe '(a b c) obtendr '((a) (b)
(c))
;;;Paso 2: Utiliza la funcin SUBST para sustituir
por NIL cada aparicin de
;;;
la expresin expr
;;;Paso 3: Aplica mediante APPLY la funcin APPEND a
los miembros de la lista.
;;;
de esta manera desaparecen los NIL
(listas vacas) que sustituyeron
;;;
a la expresin eliminada
(defun remove (expr lst)
(apply 'append (subst nil (list expr) (mapcar
'list lst)))
)
Ejemplo:
_$ (remove 'a '( b c d f a g h j))
(B C D F G H J)
_$
Extraccin de los vrtices de una Polilnea:

En un captulo anterior, al estudiar los procesos recursivos,


habamos desarrollado una funcin destinada a extraer los
valores de los vrtices de una polilnea. Con los procesos que
hemos estudiado hasta ahora pudiramos intentar el
enunciado de una funcin ms concisa y clara para obtener
este resultado. A ello dedicaremos el prximo apartado.

EXTRACCIN DE LOS VRTICES DE UNA POLILNEA:


Una manera ms eficaz de abordar el problema.

El programa expuesto en el captulo sobre los procedimientos


recusivos, ha sido elaborado utilizando slo las funciones
primitivas conocidas entonces de AutoLISP. Una manera ms
eficaz de encarar su anlisis sera la de tener en cuenta si
algunos de los procesos que se llevan a cabo dentro del
mismo pudieran programarse independientemente, como
funciones utilitarias. Una funcin utilitaria es un nuevo operador
que aadimos al lenguaje de programacin para resolver
situaciones que pueden presentarse con cierta frecuencia
dentro de nuestros programas. En el caso que estamos
analizando, podemos concebir la necesidad de una nueva
funcin que recorra una lista y de acuerdo con el resultado de
una funcin que se le pase como predicado elimine unos
trminos y conserve otros. Como resultado tendramos una
lista que slo incluyera los trminos deseados, en este caso
las listas de asociacin identificadas con los cdigos 10. Estas
funciones que pudiramos llamar QUITAR-SI y su
complementaria QUITAR-SI-NO han estado siempre entre las
primeras que los programadores LISP han aadido a su
repertorio de utilidades. Una definicin de las mismas pudiera
ser:
;;;QUITAR-SI
;;;Implementacin de la funcin REMOVE-IF
;;;en contexto AutoLISP
(defun quitar-si (predicado lista)
(cond
((null lista) nil)
((apply predicado (list (car lista)))
(quitar-si predicado (cdr lista))
)
(t (cons (car lista)(quitar-si predicado (cdr
lista))))
)
)
;;;QUITAR-SI-NO
;;;Implementacin de la funcin REMOVE-IF-NOT
;;;en contexto AutoLISP
(defun quitar-si-no (predicado lista)

(cond
((null lista) nil)
((apply predicado (list (car lista)))
(cons (car lista)(quitar-si-no predicado (cdr
lista)))
)
(t (quitar-si-no predicado (cdr lista)))
)
)
Tanto es as que se han incorporado como operadores a la
norma de Common LISP bajo los nombres de REMOVE-IF
(QUITAR-SI) y de REMOVE-IF-NOT (QUITAR-SI-NO). Visual
LISP les incorpora el prefijo VL- para distinguirlos de las
funciones del antiguo AutoLISP, y as las encontraremos en el
catlogo de funciones Visual LISP como VL-REMOVE-IF y VLREMOVE-IF-NOT.
Utilizando VL-REMOVE-IF-NOT y con la ayuda de la funcin de
mapeado sobre listas MAPCAR, estudiada en el apartado
anterior, nuestra funcin VertPoly pudiera escribirse de la
siguiente manera:
;;;Funcin VertPoly utilizando VL-REMOVE-IF-NOT
;;;Paso 1:
;;;Eliminar todos las sublistas que no correspondan
al cdigo 10
;;;Paso 2:
;;;Extraer el CDR de cada una de las sublistas.
;;;Se utiliza el mapeado de la funcin CDR a la
lista mediante MAPCAR
;;;Paso 3:
;;;Se aade el valor de la elevacin mapeando a la
lista una expresin LAMBDA.
(defun VertPoly (lista elevacion)
(mapcar
;Paso 3
(function (lambda (x) (append x (list
elevacion))))
(mapcar
;Paso 2
'cdr
(vl-remove-if-not
;Paso 1
(function (lambda (x) (equal (car x)
10)))
lista

) ;_ fin de vl-remove-if-not
) ;_ fin de mapcar
) ;_ fin de mapcar
) ;_ fin de defun
Obsrvese el uso de la funcin FUNCTION que fuerza la
compilacin de las dos expresiones-LAMBDA. Se utiliza en
lugar de QUOTE (o apstrofe) procurando una mayor eficacia y
rapidez.
Esta segunda formulacin resulta ms clara y ms econmica
en cuanto a esfuerzo de programacin. Por otra parte, supera
las limitaciones de Visual LISP en cuanto a la recursin que
pudiera provocar en caso de polilneas con un gran nmero de
vrtices un error por desbordamiento de pila.
Nota: esta funcin devuelve los resultados correctos para
Visual LISP en AutoCAD 2000. Sin embargo hemos
encontrado que falla si se ejecuta desde el IDE Visual LISP
para la versin 14. El error se encuentra en los valores de la
lista de asociacin para el objeto LWPOLYLINE que se
obtienen desde este entorno:
(entget(car(entsel))) aplicado a una LWpolyline en la
lnea de comandos de AutoCAD R14 devuelve:
Command: (entget(car(entsel)))
Select object:
((-1 . <Entity name: 43b0500>) (0 . "LWPOLYLINE") (5
. "20")
(100 . "AcDbEntity") (67 . 0) (8 . "0") (100 .
"AcDbPolyline")
(90 . 7) (70 . 0) (43 . 0.0) (38 . 0.0) (39 . 0.0)
(10 103.882 154.494) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 180.771 201.906) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 186.224 143.05) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 267.476 167.028) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 256.569 105.994) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 298.558 123.432) (40 . 0.0) (41 . 0.0) (42 .
0.0)

(10 293.651 89.1) (40 . 0.0) (41 . 0.0) (42 . 0.0)


(210 0.0 0.0 1.0))
Obsrvese que las listas asociadas al cdigo 10 contienen dos
nmeros reales adems del cdigo de asociacin: (10
256.569 105.994) es decir, las coordenadas X e Y solamente.
Sin embargo, al ejecutarlo desde la consola de Visual LISP
aparece un tercer nmero real: (10 256.569 105.994 0.0),
representando el valor de Z:
_$ (entget(car(entsel)))
((-1 . <Entity name: 43b0500>) (0 . "LWPOLYLINE") (5
. "20")
(100 . "AcDbEntity") (67 . 0) (8 . "0") (100 .
"AcDbPolyline")
(90 . 7) (70 . 0) (43 . 0.0) (38 . 0.0) (39 . 0.0)
(10 103.882 154.494 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 180.771 201.906 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 186.224 143.05 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 267.476 167.028 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 256.569 105.994 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 298.558 123.432 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(10 293.651 89.1 0.0) (40 . 0.0) (41 . 0.0) (42 .
0.0)
(210 0.0 0.0 1.0))
_$
Este comportamiento constituye un error que ya ha sido
superado en la versin
Cundo usar la Recursin y cundo la Iteracin?

Tomado del tutorial por Collin Allen y Maneesh


Dhagat, April 1997.
Traduccin del ingls: Reinaldo Togores, 1999.
Hay muchos problemas para los cuales la recursin resulta natural y para los cuales
la iteracin resulta extremadamente difcil. Esto sucede usualmente cuando se

tienen en cuenta objetos con una estructura compleja de listas anidadas. Por
ejemplo, consideremos esta expresin matemtica en formato LISP:

(setq math-formula
'(+ 3 (* (- 5 pi) 4 (/ 3 7))(* 15 2))
)
Math-formula contiene listas dentro de listas dentro de listas.

Supongamos que quisiramos saber cuntos nmeros estn


sepultados en las profundidades de esta frmula. He aqu una
funcin recursiva que lo averiguar:
(defun num-nums (mf)
(cond
((null mf) 0)
no contiene ninguno
((numberp (car mf))
trmino es un nmero
(1+ (num-nums (cdr mf))))
nmero en el resto
((atom (car mf))
cualquier otro tomo
(num-nums (cdr mf)))
contar el resto
(t (+ (num-nums (car mf))
una lista a contar
(num-nums (cdr mf))))))
numero en el resto

;; la lista vaca
;; si el primer
;; sumar al
;; si es
;; ignorarlo,
;; o se trata de
;; y sumar al

Pruebe esta funcin y examine su operacin usando TRACE. Observe que la


profundidad de recursin flucta a medida que las sublistas son procesadas.

>(num-nums math-formula)
1> (NUM-NUMS (+ 3 (* (- 5 PI) 4 (/ 3 7)) (* 15
2)))
2> (NUM-NUMS (3 (* (- 5 PI) 4 (/ 3 7)) (* 15
2)))
3> (NUM-NUMS ((* (- 5 PI) 4 (/ 3 7)) (* 15
2)))
4> (NUM-NUMS (* (- 5 PI) 4 (/ 3 7)))
5> (NUM-NUMS ((- 5 PI) 4 (/ 3 7)))
6> (NUM-NUMS (- 5 PI))
7> (NUM-NUMS (5 PI))
8> (NUM-NUMS (PI))
9> (NUM-NUMS NIL)
<9 (NUM-NUMS 0)

<8 (NUM-NUMS 0)
<7 (NUM-NUMS 1)
<6 (NUM-NUMS 1)
6> (NUM-NUMS (4 (/ 3 7)))
7> (NUM-NUMS ((/ 3 7)))
8> (NUM-NUMS (/ 3 7))
9> (NUM-NUMS (3 7))
10> (NUM-NUMS (7))
11> (NUM-NUMS NIL)
<11 (NUM-NUMS 0)
<10 (NUM-NUMS 1)
<9 (NUM-NUMS 2)
<8 (NUM-NUMS 2)
8> (NUM-NUMS NIL)
<8 (NUM-NUMS 0)
<7 (NUM-NUMS 2)
<6 (NUM-NUMS 3)
<5 (NUM-NUMS 4)
<4 (NUM-NUMS 4)
4> (NUM-NUMS ((* 15 2)))
5> (NUM-NUMS (* 15 2))
6> (NUM-NUMS (15 2))
7> (NUM-NUMS (2))
8> (NUM-NUMS NIL)
<8 (NUM-NUMS 0)
<7 (NUM-NUMS 1)
<6 (NUM-NUMS 2)
<5 (NUM-NUMS 2)
5> (NUM-NUMS NIL)
<5 (NUM-NUMS 0)
<4 (NUM-NUMS 2)
<3 (NUM-NUMS 6)
<2 (NUM-NUMS 7)
<1 (NUM-NUMS 7)
7
Sera difcil definir num-nums de forma iterativa. No es imposible, pero exige el
saber utilizar una pila para simular la recursin.

Muchas tareas de inteligencia artificial implican el buscar a


travs de estructuras anidadas. Por ejemplo, las
representaciones en rbol de los movimientos en un juego se
representan mejor como listas anidadas. Examinar este rbol
implica un rastreo recursivo a travs del mismo. Para este

tipo de aplicacin las funciones recursivas resultan una


herramienta esencial.
Cundo debemos utilizar la iteracin y cundo la recursin?
Hay por lo menos estos tres factores a considerar:
(1)
La funciones iterativas son usualmente ms rpidas que
sus contrapartes recursivas. Si la velocidad es
importante, normalmente usaramos la iteracin.
(2)
Si la memoria de pila es un limitante, se preferir la
iteracin sobre la recursin.
(3)
Algunos procedimientos se programan de manera
recursiva de forma muy natural, y resultan
prcticamente inabordables iterativamente. Aqu la
eleccin es clara.
Recursin por la Cola (Tail-Recursion)

Tomado del tutorial de Collin Allen y Maneesh


Dhagat, April 1997.
Traduccin del ingls: Reinaldo Togores, 1999.
El punto (1) ms arriba es slo una regla aproximada. Al
compilar el cdigo LISP (un compilador toma el cdigo escrito
en un lenguaje de programacin y lo convierte en lenguaje de
mquina binario para hacerlo operar a mayor velocidad)
algunos compiladores son suficientemente inteligentes como
para distinguir los procesos recursivos por la cola (tailrecursive) de los que no lo son. Ninguno de los ejemplos
anteriores de funciones recursivas son recursivos por la cola
(tail-recursive). Para serlo, el resultado devuelto por la
llamada al nivel superior de la funcin debe ser idntico al
valor resultante de la llamada al ltimo nivel. En la
informacin obtenida mediante TRACE al ejecutar la funcin
FACTORIAL descrita anteriormente podemos ver que el
resultado definitivo, 24, no es el mismo que lo devuelto por el
ltimo nivel que fu 1. As vemos que FACTORIAL no es una
funcin recursiva por la cola o tail-recursive.

La siguiente funcin tiene la propiedad de ser recursiva por la


cola:
(defun mi-max (nums)
;; busca el
mayor
(cond ((= (length nums) 1) (car nums)) ;;
terminacin
((> (car nums) (cadr nums))
;; primero
> segundo as que
(mi-max (cons (car nums)
(cddr nums))))
;; se
elimina el segundo
(t (mi-max (cdr nums)))))
;; de lo
contrario, el primero
Si se aplica TRACE a esta funcin operando sobre una lista de
nmeros tendramos algo como esto:
>(MI-MAX '(1 3 412 43 1 1 3412 53 43 43 54))
1> (MI-MAX (1 3 412 43 1 1 3412 53 43 43 54))
2> (MI-MAX (3 412 43 1 1 3412 53 43 43 54))
3> (MI-MAX (412 43 1 1 3412 53 43 43 54))
4> (MI-MAX (412 1 1 3412 53 43 43 54))
5> (MI-MAX (412 1 3412 53 43 43 54))
6> (MI-MAX (412 3412 53 43 43 54))
7> (MI-MAX (3412 53 43 43 54))
8> (MI-MAX (3412 43 43 54))
9> (MI-MAX (3412 43 54))
10> (MI-MAX (3412 54))
11> (MI-MAX (3412))
<11 (MI-MAX 3412)
<10 (MI-MAX 3412)
<9 (MI-MAX 3412)
<8 (MI-MAX 3412)
<7 (MI-MAX 3412)
<6 (MI-MAX 3412)
<5 (MI-MAX 3412)
<4 (MI-MAX 3412)
<3 (MI-MAX 3412)
<2 (MI-MAX 3412)
<1 (MI-MAX 3412)
3412

Observe que el resultado 3412 se transmite sin cambios


desde el nivel inferior hasta el superior. MI-MAX es, por lo
tanto, una funcin recursiva por la cola o tail-recursive.
Al compilar el cdigo LISP, un compilador "listo" es capaz de
reconocer la recursividad por la cola o tail-recursion, cortando
el proceso tan pronto como se obtiene el resultado para el
ltimo nivel. De esta manera se puede incrementar de
manera significativa la velocidad de procesamiento en las
funciones recursivas.

Este documento est en preparacin. Agradecer cualquier


opininin, sugerencia o consulta que pudieras hacerme para
mejorarlo. Para enviar tu aporte, escrbelo en el recuadro de
abajo y pulsa el botn ENVIAR.
Nombre y Apellido:
E-mail:

Enviar

Borrar

Potrebbero piacerti anche