^ __|__ _ _ | | | | | | | | | | | | | \ |_| |_____| |__ | __| | | | | ----> |_____| Peculiar enfoque ________________ Lisp intenta traducir el funcionamiento de cualquier computador al modo en que opera la lógica abstracta (actitud idealizadora, aplicable sobre todo tipo de arquitecturas de procesador), mientras C recorre el camino opuesto : pretende acercar el pensamiento humano a la forma real en que funcionan la mayoría de los procesadores (pragmatismo). C es el lenguaje de preferencia para manejar la máquina -proporciona dominio total sobre lo que hay en memoria- pero se restringe a aparatos con la denominada "arquitectura clásica" (misma memoria para programa que para datos y mismo modo de acceder a periféricos que a memoria). Su amplia aceptación ha influido a su vez sobre los fabricantes de hardware, que se han visto obligados a elaborar productos que sean adecuados para C. El programador C debe por tanto ajustar su forma de escribir a la manera en que funciona la maquinaria, mientras en Lisp se debe escribir pensando fundamentalmente en el lector humano. Ese mayor nivel de abstracción permite llegar a programar algoritmos más complejos (expresividad). Para ello el primer paso es independizar -poderse olvidar- de TODO lo subyacente, llegando incluso a no presuponer ni siquiera la existencia de sistema operativo, por lo cual todo compilado Lisp necesita lanzarse desde dentro del intérprete, lo que puede resultar sorprendente. El objetivo original era de hecho unificar la idea de sistema operativo y lenguaje de programación, eliminando la distinción entre ambos. Eso fue en realidad lo que condujo a tener un lenguaje que se puede ejecutar tanto compilado como interpretado, no la ventaja suplementaria que se obtiene que es acelerar el depurado. Por lo mismo que no hace distinciones entre instrucciones típicas de un sistema operativo y las propias de un lenguaje de programación, tampoco distingue entre las primitivas del lenguaje y las que corresponderían a bibliotecas de programas. Todas son tratadas exactamente igual. Como consecuencia, crear una función o una variable es estrictamente equivalente a ampliar el propio lenguaje. Eso ha llevado a un standard con una enorme cantidad de palabras reservadas. Aunque, nuevamente, si el usuario se lo propone las puede redefinir (con lo que no son en realidad reservadas). Muy pocas de ellas son imprescindibles : Probablemente Lisp sea de hecho el lenguaje definible usando la menor cantidad posible de elementos (En origen solamente 7 : quote, atom, eq, car, cdr, cons y cond). Importante : Que se pueda reasignar por ejemplo la variable NIL no significa que sea recomendable hacerlo, ya que algo así puede causar mal funcionamiento. Muchas implementaciones incorporan barreras de seguridad (desactivables). Peculiares coincidencias ________________________ Lisp se centra en trabajar con cosas que se encuentren en memoria. En contraste, las herramientas de un sistema operativo suelen ir enfocadas a operar desde y sobre los programas y datos que residen en soporte material. Por ejemplo, el compilador C trabaja exclusivamente sobre archivos, pero Lisp permite compilar conjuntos de instrucciones directamente en memoria. Las llamadas a código compilado e interpretado se pueden entremezclar. No obstante, su filosofia fue adoptada por Unix y coincide en lo siguiente : - Tanto los programas como los datos se guardan en forma de ficheros. (programas = datos) - Todos los ficheros son flujos (streams) de datos, sin estructura interna por encima del byte (con solamente entrada & salida). bit = binary digit byte = octeto = 8 bits (4+4) En Unix se suelen leer y procesar línea a línea ("line-oriented"), pero Lisp fue pensado para poder manejar una entrada con cualquier estructura. - El concepto del bucle "repl" ( "read-eval-print" loop, o "listener" ) es muy similar al de "shell" y nace con la idea A.I. de usar un lenguaje para "conversar" con la máquina. - Disponer de intérprete hace preferible el texto llano dentro de los ficheros (programas = datos) usando formatos binarios solamente en lo imprescindible. - En Unix el formato de la salida de todo programa debe ser adecuado para poder usarse como entrada de cualquier otro programa. homoiconic = En Lisp incluso el formato en el que se encuentra escrito el propio programa debe ser adecuado para poder usarse como entrada de otro. - Dentro de una instrucción, la primera palabra es la que determina lo que se invoca, siendo las posteriores datos que se le entregan (en shell tal cual, pero en el repl tras substituir lo que simbolicen). En Lisp esta notación de prefijo no admite excepciones. - Preferir llamadas a funciones (planteamiento funcional o declarativo) en lugar de saltos a subrutinas (enfoque procedural o imperativo). - Intentar distribuir el funcionamiento en multitud de pequeños componentes. arquitectura = manera en que se divide algo en componentes y se establecen unas formas fijas de comunicarse (interfaces) entre ellos. Hay arquitecturas acertadas y no. Las buenas suelen tener larga vida porque facilitan gestionar la complejidad y los cambios sucesivos. (Bill Strecker, de Digital) - Buscar la ortogonalidad (independencia total) entre los componentes. - Evitar todo lo posible duplicar código. - Unificar en un solo standard reconocido. ( Common Lisp ha tenido en la práctica un éxito entre su comunidad mayor incluso que el que ha tenido POSIX en la suya : Scheme ya ni siquiera incluye la palabra Lisp en su nombre ). Peculiar forma de representar _____________________________ C unifica la idea de variable y de dato (la variable ES el dato), pero en Lisp son cosas separadas (programación simbólica, lo que permite "dynamic typing" y evita tener que hacer link tras compilar). Las variables son de hecho lo que en C se llama punteros. La noción de dato como algo a lo que se apunta desde otro dato (por ejemplo desde un nombre de variable) conduce de forma inmediata a la posibilidad de construir encadenamientos sucesivos de datos, lo que elimina por otro lado la necesidad de reservarles por anticipado espacio en la memoria : Son las denominadas listas. En Lisp se ha puesto un énfasis en ellas que ha resultado excesivo, pues las denominadas en C estructuras son las que han acabado cumpliendo el importante papel que en programación se esperaba que iba a corresponder a las listas. La razón fundamental es que las listas son por su propio diseño más lentas que aquellas construcciones en las que se acceda directamente a cualquiera de los componentes sin tener que atravesar otros. De hecho, es recomendable utilizarlas lo menos posible para representar datos incluso cuando se programe en Lisp, en contra de lo que tanto se insiste por tradición : Si se acude a vectores y otros tipos (las estructuras también se pueden utilizar en Lisp) se declaran todos ellos, y se compila -no se ejecuta interpretado- la velocidad de ejecución de Lisp es equiparable a la de C/C++. Originariamente era su única forma de manejar datos, pretendiendo lograr el ideal "en Lisp todo es una lista". Los vectores, estructuras y todos los otros tipos son átomos. El propio programa es una lista, por lo que crear programas desde otro programa Lisp es tan fácil como en otros lenguajes crear un vector. Peculiar escritura (tipografía) _______________________________ Las extensiones de archivo usuales son : .lisp .lsp .lis .l lisp interpr. (src.) cod. .cl common lisp .el emacs lisp .elc emacs lisp (compil.) .scm .ss Scheme src. cod. .fasl .fsl .fas .pfsl .ufsl compil. bytecode ("fast load") .o .x86fsl .x86f .sparcf .xbin compil. obj. .core .mem .dxl .psv .sysout imagen de la memoria (volcado del "mundo" lisp) En Lisp existe cierta preferencia por extensiones de solamente 3 caracteres (por ejemplo, htm sobre html) debido a la diversidad de sistemas y hardware raro en su larga historia. Por el mismo motivo no distingue letras minusc. de Mays. y en rigor no admite vocales acentuadas ni otros caracteres no ingleses ni siquiera dentro de comentarios. Lisp de hecho es anterior a ASCII. Su característica más visible y conocida es sin embargo otra : En el resto de entornos se suelen utilizar multitud de caracteres para agrupar las cosas - tipicamente }:{;],[ y otros - pero Lisp impone exclusivamente los parentesis ( ) para ese fin. La sintaxis se simplifica de esta forma hasta el extremo, a costa de producir una impresión de monotonía también extrema : Su elegante sencillez es a la vez su fealdad. Para escribirlo acaba siendo desafortunadamente indispensable usar un programa que ayude a asociar cada parentesis con su pareja, dado que esa constituye la primera fuente de errores de escritura. Peculiar vocabulario (terminología) ___________________________________ Se recomienda evitar leer este apartado excepto para consulta. Lisp maneja ideas diferentes a las de otras tradiciones, e incluso las palabras que coinciden pueden tener un significado distinto del usual. El orden NO alfabético y la relativa distancia al margen (= "pretty-printing") tienen como finalidad ayudar a situar los conceptos. print, printer, printing = se refieren a presentar en pantalla, no a imprimir hardcopy = imprimir read,reader= entrada de datos desde un stream, no un lector humano stream = flujo = fichero cuyo formato no requiera estar completo para poder comenzar su lectura y tratamiento (ejemplo = texto ASCII) paren = paréntesis ( ) semi = semicolon = punto y coma ; lisp = to speak imperfectly = balbucear ( lisper = tartamudo; que balbucea ) Note : Lisp es originariamente un infinitivo. La característica definitoria es : Usar exclusivamente paréntesis como delimitadores de cierre al escribir programas, lo que impone el anidamiento. (To use exclusively parens as closing delimiters when writing programs, thereby enforcing nesting). program = programa = una secuencia preestablecida de operaciones procedure = procedimiento = representación mental de aquello que sucede process = proceso = lo que sucede realmente al ejecutar un programa gc = garbage collection = garbage collector = Lo que evita tener que liberar explícitamente el espacio en memoria que ya no se usa. Los datos ya no usados son eliminados y su espacio recuperado pero no sus símbolos, que pueden persistir tras dejar de usarse. extent = duración = ámbito de vigencia de un _dato_ (no de su valor) dynamic extent = pass-by-name = pasar el nombre = usar los mismos datos. Trabajar con los datos originales, no con copias de sus valores. No implica nada acerca de si distintos nombres de variable pueden apuntar al mismo dato (como en Lisp) o no (como en BASIC y C). syntactic extent = pass-by-value = pasar sólo el valor = usar otros datos. Cuando los datos adscritos a variables dentro de una función nunca son accesibles desde fuera de esa función. Usualmente implica "syntactic scope", porque la existencia simultánea de datos distintos -aunque sean de igual valor- implica que sus variables son necesariamente distintas (como sucede en C), pero en Lisp una variable puede almacenar datos distintos (de los que solamente el último está activo). pass-by-reference = el dato que se duplica es un acceso al dato original. Convierte pass-by-value en pass-by-name, es decir, un dato local en global, algo innecesario en Lisp. scope = visibilidad = ámbito de vigencia de una _variable_ static scope = no se permite reasignar valores a los nombres de variables o sea, que en realidad son constantes. Se da en lenguajes muy arcaicos y lleva normalmente asociado static typing. dynamic scope = usar las mismas variables. Cuando no existe distinción entre variables locales y globales (como sucede en BASIC). Implica pass-by-name (dynamic extent). syntactic scope = usar otras variables, aunque puedan tener el mismo nombre. Una variable que se defina dentro de una función no va a ser la misma que las de igual nombre definidas fuera de esa función. No implica necesariamente pass-by-value : pueden estar indicando el mismo dato y no solamente el mismo valor (como sucede en Lisp). ________________________________ ___________________________________ / ___________ _\/_ ___________ \ / / BASIC \ / \ / C \ \ | | | | LISP | | | | | | dynamic scope | pass-by-name | | syntactic scope | pass-by-value | | | | Mismas vars. | Mismos datos \ / Otras variables | Otros datos | | \ \_____________/ \ / \_____________/ / \__________________________________/\_____________________________________/ creciente estilo funcional ----> weakly typed = tipificado débil (ejemplos : string=vector , entero=indefinido 16, 32 bits...) aunque no en el mismo grado que C (En Lisp, char no es int). static typing = tipificado estático = cuando la variable y el dato son la misma cosa, por lo que el tipo de dato pasa a ser una propiedad de la variable dynamic typing = tipificado dinámico = cuando el tipo es una propiedad del dato pero no de la variable. No se debe relacionar con tipificado débil, ni con "dynamic scope" o "dynamic extent", descritos anteriormente. Es prácticamente un sinónimo de programación simbólica, pues la requiere. Common Lisp permite para cada variable mediante declaraciones especificar tipo estático o mediante su ausencia establecer tipo dinámico. Lo mismo en cuanto a la visibilidad. tipo = aquello que determina las operaciones que son aplicables a un dato (ejemplos = entero, secuencia de caracteres...) objeto = dato que pertenece a un tipo no predefinido en el lenguaje, sino especificado por programa (usualmente como una estructura cuyos componentes son funciones y datos de otros tipos o clases) Solamente se pueden componer a partir de los ya existentes. first-class = analogía con "ciudadano de primera clase" (mismos derechos) Objeto con el que se puede hacer las mismas cosas que con los de otros tipos (crearlo al vuelo, asignarlo a alguna variable, etc.) orientado = que no permite programar en otros estilos (oriented = biased) CLOS = Common Lisp Object System. A partir del standard ANSI ya no existe como algo separado de Common Lisp. funcional = el resultado depende exclusivamente del valor de los argumentos en el momento de invocar -lo que implica declarar obligadamente como argumento todo aquello que pueda influir en el resultado- y no debe modificar nada, ni siquiera los propios argumentos (no se deben ejercer efectos secundarios). Si un objetivo de la "programación estructurada" es eliminar todos los "goto", la "programación funcional" persigue eliminar todas las asignaciones a variables. Mientras pass-by-value prácticamente garantiza un estilo funcional pass-by-reference garantiza su ausencia. Contra lo que se suele decir, no tiene nada que ver con tratar a las funciones como objetos de primera clase (programas = datos). macrology = macrología. El arte de utilizar macros adecuadamente. macro = En general, código que no produce resultados finales sino otro código que lo substituye. statement = enunciado = no entrega ningún resultado (ejemplos = declare, quit) (Contrariamente a lo que se pretende, en Lisp también existen) assertion = aseveración = statement que determina el modo en que se tratan datos o resultados. expression = Código que entrega algún resultado. M-exp = meta-expression = notación matemática tradicional equivalente. S-exp = symbolic expression = o un átomo, o algo delimitado con paréntesis. atom = átomo = que no tiene componentes. El átomo AB no se puede descom- poner en A y B ni necesariamente tener relación alguna con A o B. Puede ser no simbólico, o un símbolo. non-symbol = no representa nada distinto de sí mismo (ejemplo = número) Note : Un átomo no simbólico sigue siendo una expresión simbólica. symbol = S-atom = representa alguna otra cosa (ejemplo = variable) Originariamente implementado como un conjunto de 4 componentes : (pname = print-name) el string de su nombre, su valor como dato, su defi- nición como función, y una lista de propiedades (plist) ampliable. variable = En Lisp, símbolo global al que NO se asigna un dato en el momento de definirlo si tiene ya alguno asignado. parámetro = En general, toda variable o constante. En Lisp, constante : símbolo global que es asignado forzosamente (DEBE tener ese valor) package = equipaje No tiene que ver con empacar o compactar archivos. = entorno de símbolos (nombres de variables, funciones, etc.) de los que algunos se dejan accesibles para el resto de entornos. En Lisp se puede ir de uno de estos espacios de nombres a cualquier otro, o combinarlos. Con ello el encapsulamiento queda separado del sistema de objetos. interned = interiorizado = accesible, referible desde algún "package". uninterned = no accesible desde ningún entorno de símbolos. cons = a dotted pair, or a list = un par ordenado, o una lista. Significa construcción o constructor, no constante. list = encadenamiento de conses sucesivos teniendo nil como base/extremo . Es el convenio aceptado para representar secuencias en Lisp. nil = lista vacía; la mínima posible. Es simultáneamente atom non-symbol. En Lisp la falsedad lógica no se iguala al cero, sino a nil. Se considera verdadero todo lo que no sea nil, incluyendo el cero. singleton = solitón = lista de un solo (miembro). set = conjunto = lista en la que ninguno de sus elementos se repite. alist = association list = todos sus elementos son pares ordenados. plist = property list = cualquier lista con un número par de elementos. El emparejamiento se establece al procesar (setf (get plist 'ind.) hash = embrollo = algo de lo que no se necesita conocer su estructura para utilizarlo. oblist = obarray = hash (ni lista ni vector) tabla de todos los atomos. form = cualquier lista que simboliza acciones/operaciones, no solo datos. Su primer elemento debe estar definido como funcion o bien como special-form (por ejemplo, macro). En caso contrario no es form, y debe -como toda lista que no lo es- o bien aparecer dentro de un special-form o bien estar precedida por el caracter ' (quote). Toda lista que se introduzca en el primer nivel del intérprete Lisp debe ser necesariamente form para poder evaluarse. function = función = en matemáticas, aplicación (produce 1 solo valor) entre conjuntos numéricos, pero en Lisp "form" que evalúa previamente todos sus argumentos. Puede entregar más de 1 resultado (a diferencia de lo que sucede en C) variadic = que acepta cualquier numero de argumentos higher-order = de orden superior = que toma otras funciones como args. predicate = FUNCION cuyo resultado es o "verdadero" o "falso" logical = boolean = VARIABLE cuyo valor es o "verdadero" o "falso" combinator = función que no utiliza variables fuera de sus argumentos Y-combinator = aquella función Y , tal que (f (Y f)) -> (Y f) Es el fundamento teórico de la recursividad. recursion = cuando una función se invoca a ella misma tail-recursive = tras autoinvocarse no opera con el resultado nesting = anidamiento = toda recursividad es necesariamente anidada, aunque no todo procesamiento anidado es necesariamente recursivo: x^3 + x^2 + x + 1 = (((1) x + 1) x + 1) x + 1 Anidado y recursivo. x^3 + 2 x^2 + 7 x + 4 = ((x + 2) x + 7) x + 4 Anidado no recursivo. reentrant = que no se elimina de la memoria esperando volver a usarse. Por ejemplo, una recursividad. Implica ser de solamente lectura. closure = clausura = función que se crea como resultado de otra y que a partir de entonces conserva un entorno de valores propio. No depende de los valores de las variables en el entorno desde el que se invoca, sino desde el que fue creada. Es una consecuencia por una parte de tratar a las funciones como objetos de primera clase, y por otra del "syntactic scope". Otro significado = Cierta propiedad en los objetos matemáticos, por ejemplo, Lisp es "cerrado" sobre el conjunto de todas las listas. continuation = pila de todas las llamadas a funciones pendientes de retorno, que es memorizada. Cuando es recuperada suplanta totalmente a la de ese momento, que se olvida (ya actuará gc). coroutine = corrutina = subprograma que transfiere el control sin haber terminado y que se puede retomar mediante una continuación. Cuando se vuelve a llamar sigue donde se había interrumpido en lugar de comenzar de nuevo como lo haría una subrutina. En otras palabras, conserva el estado del control de flujo, no solamente el estado de los datos. special-form = expresión que NO evalúa previamente todos sus argumentos. Cada special-form se evalúa de un modo diferente (es lo pretendido) En Lisp los macros pertenecen como subconjunto a los special forms. lambda-calculus = formulación de las funciones como procedimientos, abstrayendo las variables lambda-form = cons del símbolo lambda, lambda-exp, y valores de args. Siempre substituible por una expresión con let (otro special-form) lambda (símbolo) = "para todo ..." : lambda (x y) = para todo x e y lambda-exp = cons de lambda-list y form. Equivale al nombre de función y por tanto puede reemplazarlo si se precede del símbolo lambda. Se suele confundir con lambda-form. lambda-list = solo contiene variables (ni datos ni operaciones) unwind = destensar, o soltar del todo, algo que estaba enrollado, como la cuerda de un reloj o -figuradamente- el stack de llamadas pendientes de retorno. introspectivo = capaz de autoexaminarse. Lisp es un lenguaje introspectivo. Permite operar sobre el propio lenguaje, sobre sus objetos (inspect = describe + disassemble) y sobre los procedimientos en ejecución (step = trace + break) con un nivel de control que recuerda al que C permite sobre el hardware. inferencia = acto de obtener una deducción lógica inducción = recursividad aplicada dentro de la lógica heurístico = que no garantiza proporcionar siempre una solución En caso que la única solución admisible sea la óptima, significa que renuncia a garantizar la solución óptima. random = unpredictable = impredecible (No es lo mismo que al azar). means-ends = medios-fines = cierto algoritmo genérico consistente en expandir el arbol de posibilidades buscando cancelaciones mutuas. CRT = Cathode Ray Tube = tubo de imagen de pantalla de televisor CPT = Character Printing Terminal = consola que solamente puede mostrar caracteres tipográficos completos, no puntos individuales. ddt = dynamic debugging tool En Lisp no se necesita, pues la herramienta de depurado va incorporada en el propio lenguaje. Uso elemental _____________ Invocar : alisp allegro common lisp gcl common lisp de GNU ecl common lisp embebible lisp common lisp de CMU & comerciales sbcl derivado de cmucl openmcl derivado de Mcl (solamente para tipos de procesador Power o amd64) clisp common lisps europeos Salir del bucle de error : :q quit :a abort 0 en otras implementaciones Ctrl-Z en sistemas no-Unix Otras instrucciones interesantes no tan conocidas : (room) informar de la ocupación de memoria (gc) liberar memoria Terminar : (quit)