2009-07-09 15 views
21

He leído The Nature of Lisp. Lo único que realmente obtuve fue "código es información". Pero sin definir qué significan estos términos y por qué generalmente se los considera separados, no obtengo ningún conocimiento. Mi reacción inicial al "código es la información" es, ¿y qué?¿Cómo obtengo 'Lisp?

Respuesta

34

Escribir código Lisp. La única manera de 'obtener' realmente Lisp (o cualquier lenguaje, para el caso) es arremangarse e implementar algunas cosas en él. Al igual que cualquier otra cosa, puede leer todo lo que quiera, pero si realmente quiere tener una idea clara de lo que está sucediendo, debe salir de lo teórico y comenzar a trabajar con lo práctico.

+4

Sí, la escritura es buena, pero no servirá de mucho si solo intenta escribir el código C con sintaxis Lisp. – Svante

+9

En realidad, está bien escribir código C con sintaxis Lisp como primer paso. Nadie cambia de idioma y capta instantáneamente el nuevo paradigma en su totalidad: primero debe aprender a comprender la estructura básica de lo que está mirando, y luego puede enfocarse en resolver detalles más finos y conceptos completamente nuevos. Pero hasta que haya escrito algún código en el idioma, aprender todos los constructos no ayudará mucho. –

+10

De hecho. Los patrones se llaman patrones porque surgen por sí mismos, no están prescritos. Comience a codificar; si algo se siente bien, probablemente lo estés haciendo bien. Si algo se siente mal, probablemente lo estés haciendo mal (o usando PHP). – jrockway

9

Creo que tiene que tener más empatía con los escritores de compiladores para comprender cuán fundamental es el código para los datos. Lo admito, nunca tomé un curso de compiladores, pero convertir un lenguaje suficientemente alto en código máquina es un problema difícil, y LISP, en muchos sentidos, se asemeja a un paso intermedio en este proceso. De la misma manera que C está "cerca del metal", LISP está cerca del compilador.

+3

Lo que vi fue que Lisp te permite pensar con tu código, en lugar de esforzarte por superar la sintaxis y, con suerte, expresar lo que pretendías. Estoy aprendiendo Raqueta un poco a la vez, y es como haber sido liberado de una prisión en la que ni siquiera me daba cuenta de que estaba. Los grilletes están siendo despojados de mi pensamiento: tomé dos semestres de Java, y ahora cuando veo cuán limitado mi pensamiento había sido (¡debería haberlo sabido mejor! Soy un estudiante de física y matemáticas), siento una especie de pesar profundo pero impotente (rechazo de la autocompasión). –

+3

* (continuación) * La sensación es lo que experimentaría, quizás, después de construir su propia casa de campo, muebles y riego a mano, al enterarse de que las herramientas eléctricas estaban ampliamente disponibles. "¿Trabajé durante tanto tiempo bajo tales dificultades innecesarias?" Esto parece dramático, pero eso es lo que sentí cuando me enteré de que una tarea simple se podía hacer de una manera general, y no meramente de una manera restringida impuesta por, por ej. la sintaxis y el lenguaje de Java. Una armonía fue restaurada. Una carga fue levantada. –

2

Los datos son código es un paradigma interesante que admite tratar una estructura de datos como un comando. El tratamiento de los datos de esta manera le permite procesar y manipular la estructura de varias maneras, por ej. recorrido - evaluándolo. Además, el paradigma de "datos es código" evita la necesidad en muchos casos de desarrollar analizadores personalizados para estructuras de datos; el analizador de lenguaje en sí mismo se puede utilizar para analizar las estructuras.

-1

La forma en que lo pienso es que la mejor parte de "código es datos" es que la función de esa cara, bueno, funcionalmente no es diferente de otra variable. El hecho de que pueda escribir código que escriba código es una de las características más poderosas (y a menudo olvidadas) de Lisp. Las funciones pueden aceptar otras funciones como parámetros, e incluso devolver funciones como resultado.

Esto permite un código en un nivel de abstracción mucho más alto que, por ejemplo, Java. Hace que muchas tareas sean elegantes y concisas, y por lo tanto, hace que el código sea más fácil de modificar, mantener y leer, o al menos en teoría.

Yo diría que la única forma de realmente "obtener" Lisp es dedicarle mucho tiempo. Una vez que lo domine, desearía tener algunas de las características de Lisp en su otros lenguajes de programación.

+0

Las funciones de primera clase son agradables, pero eso no es lo que significa "código de datos". –

+0

Estoy totalmente de acuerdo con usted en que eso no es en absoluto_ lo que significa. Lo que estaba buscando es que la estructura de datos de la lista y la función sean uno en Lisp; la fusión de los dos idiomas otorga al programador ciertas habilidades que no están disponibles en otros idiomas. La lista es la información. –

0

me gustaría sugerir que es una introducción horrible al lenguaje. Hay mejores lugares para comenzar y mejores personas/artículos/libros que el que usted citó.

¿Eres programador? Que idiomas)?

Para ayudarlo con su pregunta, puede ser útil contar con más información.

1

Una de las razones por las que algunos programas universitarios de ciencias de la computación usan Lisp para sus cursos introductorios es que generalmente es cierto que un principiante puede aprender de manera más o menos igual la programación funcional, procedimental u orientada a objetos.Sin embargo, es mucho más difícil para alguien que ya piensa en declaraciones de procedimientos comenzar a pensar como un programador funcional que hacer lo contrario.

Cuando traté de recuperar Lisp, lo hice "con un acento C". set! y begin fueron mis amigos y compañeros constantes. Es sorprendentemente fácil escribir código Lisp sin siquiera escribir ningún código funcional, que no es el punto.

Notará que no respondo su pregunta, lo cual es cierto. Simplemente quería que supieras que es muy difícil lograr que tu mente piense con un estilo funcional, y será una práctica emocionante que te convertirá en un programador más fuerte a largo plazo.

Kampai!

P.S. Además, finalmente entenderás que "mi otro auto es una pegatina para el parachoques cdr".

23

La manera de "obtener" cualquier idioma es tratando de escribir algún código en él.

Acerca de la cuestión de "datos es código", en la mayoría de los idiomas existe una clara separación entre el código que se ejecuta y los datos que se procesan.

Por ejemplo, el siguiente sencillo C-como función:

void foo(int i){ 
    int j; 

    if (i % 42 == 0){ 
    bar(i-2); 
    } 

    for (j = 0; j < i; ++j){ 
    baz(); 
    } 
} 

el flujo de control real se determina una vez, estáticamente, mientras que la escritura del código. La función bar no va a cambiar, y la instrucción if al principio de la función no va a desaparecer. Este código no es información, no puede ser manipulado por el programa.

Todo lo que se puede manipular es el valor inicial de i. Y, por otro lado, ese valor no se puede ejecutar de la misma forma que el código. Puede llamar a la función foo, pero no puede llamar a la variable i. Entonces, i son datos, pero no son códigos.

Lisp no tiene esta distinción. El código del programa es información que puede ser manipulada también. Su código puede, en tiempo de ejecución, tomar la función foo, y quizás agregar otra instrucción if, quizás cambiar la condición en for-loop, quizás reemplazar la llamada al baz con otra llamada a función. Todos los códigos son datos que pueden inspeccionarse y manipularse de la misma manera que la función anterior puede inspeccionar y manipular el número entero i.

+0

+1, la mejor respuesta hasta ahora. –

+1

Eso es todo? ¿En qué se diferencia esto del código de auto modificación ?, que mi profesor llamó "una abominación" :) – MGOwen

+2

El código de auto modificación es generalmente indirecto. Usted crea un blob binario que coincide con las instrucciones de la máquina, luego lo almacena en una ubicación conocida de la memoria y luego salta a ese puntero. No recibes ninguna verificación de tipo ni nada. En particular, no hay forma de que solicite "el código fuente para la función f". Claro, puede obtener un puntero a la función y leer el código de máquina generado para ello, pero no tiene forma en el idioma para trabajar con esto. No le permite manipular el código del programa real, las cosas que escribió, en el idioma que lo escribió. – jalf

14

Recomiendo encarecidamente Structure and Interpretation of Computer Programs, que en realidad usa el esquema, pero ese es un dialecto de lisp. Te ayudará a "obtener" el ceceo haciendo que hagas muchos ejercicios diferentes y luego mostrará algunas de las formas en que lisp es tan útil.

0

Sobre todo el "código de datos es" cosa:

¿No es que debido a la "von Neumann architecture"? Si el código y los datos se ubicaban en ubicaciones de memoria físicamente separadas, los bits en la memoria de datos no se podían ejecutar, mientras que los bits en la memoria del programa no podían interpretarse como nada más que instrucciones para la CPU.

¿Entiendo esto correctamente?

+2

Parcialmente. En la mayoría de los lenguajes, la única forma de manipular o generar código fuente programáticamente es a través de cadenas opacas de texto sin formato y alguna forma de 'eval', o como una gran cadena de bytes. En Lisp, el código fuente se almacena (y es accesible para usted) como listas de objetos. Puede utilizar funciones de manipulación de lista para atravesar, transformar y generar código fuente muy fácilmente. Puede escribir macros que toman un código fuente y devuelven un código fuente diferente para el compilador/intérprete. Puedes hacer magia de esta manera. –

+0

Me da ganas de probarlo yo mismo. Gracias Brian! :-) – Kage

+0

Brian tiene razón. Añadiría que cualquiera puede escribir un intérprete, que lee datos y realiza acciones, por lo que la distinción entre datos y programas es algo que puede meditar. Es solo que esto sucede muy bien en Lisp. –

7

Esto funcionó para mí:

  1. Lea "The Little Schemer". Es el camino más corto para hacerle pensar en modo Lisp (menos las macros). Como beneficio adicional, es relativamente corto/divertido/económico.

  2. Encuentre un buen libro/tutorial para comenzar con las macros. Encontré el capítulo 8 de "El esquema Lenguaje de programación" como un buen punto de partida para Scheme.

http://www.ccs.neu.edu/home/matthias/BTLS/

http://www.scheme.com/tspl3/syntax.html

1

asimilar verdaderamente Lisp, es necesario escribirlo.

Aprenda a amar car, cdr y cons. No itere cuando pueda recurse. Comience a escribir algunos programas simples (factorial, reversión de lista, búsqueda de diccionario), y vaya subiendo a otros más complejos (clasificación de conjuntos de elementos, coincidencia de patrones).

En el código están los datos y los datos codificados, no me preocuparía en este punto. Lo entenderá eventualmente, y no es crítico para aprender lisp.

+0

Me gusta la iteración y CL tiene excelentes instalaciones para ello. Además, no explota la pila como recursión profunda (recuerde que la eliminación de TC no es necesaria en CL). Por supuesto, para un Schemer todo eso es diferente. – skypher

+0

Cuando hice Lisp en la universidad, me devolvían todas mis soluciones iterativas con el REDO GIGANTE CON RECURSIÓN DE COLA escrita sobre ellos :) Hacer ese salto de la iteración a la recursión realmente me ayudó a entender mejor los conceptos básicos del ceceo. –

2

El primer paso es olvidarse de todo lo que ha aprendido con todos los lenguajes C y Pascal. Vacia tu mente. Este es el paso más difícil.

Luego, tome una buena introducción a la programación que usa Lisp. No trates de correlacionar lo que ves con algo que sabes de antemano (cuando te sorprendas haciéndolo, repite el paso 1). Me gustó Estructura e Interpretación de Programas de Computadora (usa Scheme), Practical Common Lisp, Paradigmas de Programación de Inteligencia Artificial, Casting Spels en Lisp, entre otros. Asegúrate de escribir los ejemplos. Pruebe también los ejercicios, pero limítese a las construcciones que ha aprendido en ese libro. Si se encuentra tratando de encontrar, por ejemplo, alguna función para establecer una variable o alguna declaración que se asemeje a un bucle for, repita el paso 1, luego revise los capítulos antes para descubrir cómo se hace en Lisp.

1

Leer On Lisp y Paradigms in Artificial Intelligence Programming. Ambos tienen una excelente cobertura de macros Lisp, lo que realmente hace que el código sea real.

Además, al escribir Lisp, no itere cuando puede recurse o mapee (aprenda a amar mapcar).

+0

Buenas sugerencias, pero probablemente no como una primera incursión en Lisp. –

+0

Bah, itere cuando esa sea la mejor solución al problema ... –

54

La vista antigua: 'it' es cálculo interactivo con expresiones simbólicas.

Lisp permite representación fácil de todo tipo de expresiones:

de frases Inglés

(the man saw the moon) 

matemáticas

(2 * x ** 3 + 4 * x ** 2 - 3 * x + 3) 

reglas

(<- (likes Kim ?x) (likes ?x Lee) (likes ?x Kim)) 

y también Lisp

(mapcar (function sqr) (quote (1 2 3 4 5))) 

y muchos muchos muchos más.

Lisp ahora permite escribir programas que de cómputo con tales expresiones:

(translate (quote (the man saw the moon)) (quote german)) 

(solve (quote (2 * x ** 3 + 4 * x ** 2 - 3 * x + 3)) (quote (x . 3))) 

(show-all (quote (<- (likes Kim ?x) (likes ?x Lee) (likes ?x Kim)))) 

(eval (quote (mapcar (function sqr) (quote (1 2 3 4 5))))) 

Interactivo significa que programación es un cuadro de diálogo con Lisp. Usted ingresa una expresión y Lisp calcula los efectos secundarios (por ejemplo, salida) y el valor.

Así que su sesión de programación es como 'hablar' con el sistema Lisp. Trabajas con él hasta que obtengas las respuestas correctas.

¿Qué son estas expresiones? Son oraciones en algún idioma. Son descripciones de las turbinas en parte. Son teoremas que describen un motor de punto flotante de un procesador AMD. Son expresiones de álgebra computacional en física. Son descripciones de circuitos. Son reglas en un juego. Son descripciones del comportamiento de los actores en los juegos. Son reglas en un sistema de diagnóstico médico.

Lisp le permite escribir hechos, reglas, fórmulas como expresiones simbólicas. Le permite escribir programas que funcionan con estas expresiones. Puede calcular el valor de una fórmula. Pero también puede escribir fácilmente programas que computan nuevas fórmulas a partir de fórmulas (matemática simbólica: integrar, derivar, ...). Para eso fue diseñado Lisp.

Como efecto secundario, los programas Lisp también se representan como tales expresiones. Luego también hay un programa Lisp que evalúa o compila otros programas Lisp. Así que la idea misma de Lisp, el cálculo con expresiones simbólicas, se ha aplicado a Lisp. Los programas Lisp son expresiones simbólicas y el cálculo es una expresión Lisp.

Alan Kay (de la fama de Smalltalk) llama a la definición original de evaluación de Lisp en Lisp the Maxwell's equations of programming.

+12

Sus publicaciones continúan sorprendiéndome. Tienes una gran habilidad para comunicar los fundamentos de Lisp a los novatos. – skypher

+0

Sí. Leer sus respuestas en un orden correcto puede ser un tutorial de LISP por su cuenta. –

+0

¿Alguien quiere hacer una lista de sus publicaciones en ese orden? :RE – marczellm

1

Sugiero revisar algunas de las variantes más nuevas de Lisp como Arc o Clojure. Limpian un poco la sintaxis, son más pequeños y, por lo tanto, más fáciles de entender que Common Lisp. Clojure sería mi elección. Está escrito en la JVM y no tiene problemas con varias implementaciones de plataforma y compatibilidad de bibliotecas que existen con algunas implementaciones de Lisp como SBCL.

4

En Common Lisp, "el código es información" se reduce a esto.Cuando se escribe, por ejemplo:

(add 1 2) 

su sistema Lisp analizará que el texto y generar una lista con tres elementos: el símbolo ADD, y los números 1 y 2. Los datos así que ahora están. Puede hacer lo que quiera con ellos, reemplazar elementos, insertar otras cosas, etc.

La parte divertida es que puede pasar esta información al compilador y, debido a que puede manipular estas estructuras de datos usando Lisp, este significa que puede escribir programas que escriban otros programas. Esto no es tan complicado como suena, y Lispers lo hace todo el tiempo usando macros. Entonces, solo consigue un libro sobre Lisp y pruébalo.

0

Creo que para aprender todo lo que tiene que tener un propósito para ello, como un proyecto simple.

Para Lisp, un buen proyecto simple es un diferenciador simbólica, así que por ejemplo

(diff 'x 'x) -> 1 
(diff 'a 'x) -> 0 
(diff `(+ ,xx ,yy) 'x) where xx and yy are subexpressions 
-> `(+ ,(diff xx 'x),(diff yy 'x)) 
etc. etc. 

y luego se necesita un simplificador, como

(simp `(+ ,x 0)) -> x 
(simp `(* ,x 0)) -> 0 
etc. etc. 

por lo que si se empieza con una expresión matemática , puedes evaluarlo para obtener su valor, y puedes evaluar su derivada para obtener su derivada.

Espero que esto ilustre lo que puede ocurrir cuando el código del programa manipula el código del programa.

Como observó Marvin Minsky, la matemática informática siempre está preocupada por la precisión y el error de redondeo, ¿no? ¡Bien, esto es exactamente correcto o completamente incorrecto!

0

Puede obtener LISP de muchas maneras, la más común es mediante el uso de Emacs o trabajando junto a alguien que ya ha desarrollado LISP.

Lamentablemente, una vez que obtiene LISP, es difícil deshacerse de él, los antibióticos no funcionarán.

BTW: También recomiendo The Adventures of a Pythonista in Schemeland.

3

Bien, voy a analizar esto. Soy nuevo para Lisp, recién llegué del mundo de Python. No he experimentado ese repentino momento de iluminación del que hablan todos los viejos Lisp, pero les diré lo que estoy viendo hasta ahora.

En primer lugar, mira a este bit aleatorio de código Python:

def is_palindrome(st): 
    l = len(st)/2 
    return True if st[:l] == st[:-l-1:-1] else False 

Ahora mira esto:

""" 
def is_palindrome(st): 
    l = len(st)/2 
    return True if st[:l] == st[:-l-1:-1] else False 
""" 

¿Qué, como programador, ve? El código es idéntico, FYI.

Si eres como yo, tenderás a pensar en el primero como código activo. Consiste en una serie de elementos sintácticos.

El segundo, a pesar de su similitud, es un elemento sintáctico único. Es una cadena. Usted interactúa con él como una sola entidad. Para manejarlo como código, para manejarlo cómodamente a lo largo de sus límites sintácticos, tendrá que hacer algunos análisis sintácticos.Para ejecutarlo, necesita invocar a un intérprete. No es lo mismo en absoluto como el primero.

Entonces, cuando hacemos generación de código en la mayoría de los idiomas, ¿con qué nos enfrentamos? Instrumentos de cuerda. Cuando genero HTML o SQL con python utilizo cadenas de python como interfaz entre los dos idiomas. Incluso si genero Python con Python, las cadenas son la herramienta. *

¿No es solo por el hecho de que ... te dan ganas de bailar con alegría? Siempre hay un desajuste grotesco entre aquello con lo que estás trabajando y aquello en lo que estás trabajando. Sentí que la primera vez que generé SQL con Perl. Diferencias en escapar Diferencias en el formato: piense en intentar que un documento html generado se vea ordenado. Las cosas no son fáciles de reutilizar. Etc.

Para resolver el problema, creamos bibliotecas de plantillas en serie. Un montón de ellos. ¿Porqué tantos? Mi suposición es que nunca son bastante satisfactorios. Para el momento en que comienzan a ser lo suficientemente poderosos, se han convertido en monstruosidades. Por supuesto, algunos de ellos, como SQLAlchemy y Genshi en el mundo de las pitones, son monstruosidades muy hermosas y admirables. Vamos a ... um ... evitar mencionar PHP.

Como las cadenas constituyen una interfaz incómoda entre el lenguaje trabajado y el trabajado, creamos un tercer idioma, plantillas, para evitarlo. ** Esto también tiende a ser un poco incómodo.

Ahora vamos a ver un bloque de código Lisp citado:

'(loop for i from 1 to 8 do (print i)) 

¿Qué ves? Como un nuevo codificador Lisp, me he sorprendido a mí mismo mirando eso como una cadena. No lo es Es un código Lisp inactivo. Usted está mirando un montón de listas y símbolos. Intenta evaluarlo después de dar vuelta uno de los paréntesis. El lenguaje no te permitirá hacerlo: se aplica la sintaxis.

Usando quasiquote, podemos calzar nuestros propios valores en el código Lisp inactiva:

`(loop for i from 1 to ,whatever do (print i)) 

Nota de la naturaleza del shoehorning: un artículo ha sido sustituido por otro. No estamos formateando nuestro valor en una cadena. Lo estamos deslizando en una ranura en el código. Todo está limpio y ordenado.

De hecho, si quiere editar directamente el texto del código, no tiene problemas. Por ejemplo, si está insertando un nombre <varname> en el código, y también desea utilizar varname > -tmp en el mismo código, no puede hacerlo directamente como puede con una cadena de plantilla: "% s-tmp =% s ". Tienes que extraer el nombre en una cadena, volver a escribir la cadena, luego convertirlo en un símbolo de nuevo y finalmente insertarlo.

Si quiere captar la esencia de Lisp, creo que podría obtener más haciendo caso omiso de defmacro y gensyms y todo ese aliño de ventana por el momento. Dedica algo de tiempo a explorar el potencial del cuasiquote, incluida la cosa @. Es bastante accesible. Defmacro en sí mismo solo proporciona una manera fácil de ejecutar el resultado de cuasiquotes. ***

Lo que debe tener en cuenta es que la barrera hermética de cadena/plantilla entre el trabajado y el trabajado está prácticamente eliminada en Lisp. A medida que lo utilice, encontrará que su sentido de dos capas distintas, activas y pasivas, tiende a disiparse. Las funciones llaman a macros que llaman macros o funciones que tienen funciones (¡o macros!) Pasadas con sus argumentos. Es una especie de sopa grande, un poco chocante para el recién llegado. Dicho esto, no creo que la distinción entre macros y funciones sea tan fluida como dicen algunos Lisp.En gran parte es aceptable, pero de vez en cuando como me pregunto en la sopa me encuentro chocar contra el fantasma de esa vieja barrera - y realmente me asusta!

Lo superaré, estoy seguro. No importa. La conveniencia paga por el susto.

Ahora que Lisp está trabajando en Lisp. ¿Qué tal trabajar en otros idiomas? Todavía no he llegado del todo, personalmente, pero creo que veo la luz al final del túnel. ¿Sabes cómo siguen las personas Lisp sobre las expresiones S siendo lo mismo que un árbol de análisis? Creo que la idea es analizar el idioma extranjero en S-expressions, trabajar en ellas en la sorprendente comodidad del entorno Lisp y luego enviarlas al código nativo. En teoría, cada idioma podría convertirse en S-expressions, o incluso en código ejecutable de lisp. No está trabajando en un primer idioma combinado con un tercer idioma para producir código en un segundo idioma. Es todo, mientras trabajas en ello, Lisp, y puedes generarlo todo con cuasiquotes.

Tener un vistazo a esto (borrowed from PCL):

(define-html-macro :mp3-browser-page ((&key title (header title)) &body body) 
    `(:html 
    (:head 
     (:title ,title) 
     (:link :rel "stylesheet" :type "text/css" :href "mp3-browser.css")) 
    (:body 
     (standard-header) 
     (when ,header (html (:h1 :class "title" ,header))) 
     ,@body 
     (standard-footer)))) 

Parece que una versión S-expresión de HTML, ¿verdad? Tengo la sensación de que Lisp funciona bien como su propia biblioteca de plantillas.

Empecé a preguntarme acerca de una versión de S-expression de python. ¿Calificaría como Lisp? Ciertamente no sería Common Lisp. Tal vez sería más agradable, al menos para los programadores de Python. Oye, y ¿qué hay de P-expressions?

* Python ahora tiene algo llamado AST, que no he explorado. También una persona podría usar listas de Python para representar otros idiomas. En relación con Lisp, sospecho que ambos son un poco hack.

** SQLAlchemy es una especie de excepción. Ha hecho un buen trabajo al convertir SQL directamente en Python. Dicho esto, parece haber implicado un esfuerzo significativo.

*** Tomar de un novato. Estoy seguro de que estoy pasando por alto algo aquí. Además, me doy cuenta de que cuasiquote no es la única forma de generar código para macros. Sin embargo, es una buena idea.