2012-04-17 16 views
9
(do ((n 0 (1+ n)) 
    (cur 0 next) 
    (next 1 (+ cur next))) 
    ((= 10 n) cur))) 

Este es un ejemplo de libro de texto de Lisp sobre la palabra clave "DO"La comprensión de Common Lisp hacer sintaxis macro

el "do" plantilla básica es:

(do (variable-definitions*) 
    (end-test-form result-form*) 
statement*) 

Pero, para este ejemplo, es no está claro para mí qué parte es cuál. Y también, ¿qué hacen las líneas del medio 2?

¡Gracias!

+3

AFAIR, "do" es una macro. – zvrba

Respuesta

8

Su buena sangría muestra claramente qué parte es la que:

(do ((n 0 (1+ n)) 
    ^(cur 0 next) 
    |(next 1 (+ cur next))) 
    | 
    +-- first argument of do 

    ((= 10 n) cur))) 
    ^
    | 
    +-- start of second argument of do 

Look, que se alinea muy bien, y el material interno se sangra:

((n 0 (1+ n)) 
    (cur 0 next) 
    (next 1 (+ cur next))) 
    ^
    | 
    +- inner material of argument: three forms which are 
     indented by 1 character and aligned together. 

Su do no tiene un tercer argumento que hay: no hay cuerpo de s tatements (bucle vacío).

23
(do ((n 0 (1+ n)) ;declares n, initially 0, n+1 each subsequent iteration) 
    (cur 0 next) ;declares cur, initially 0, then old value of next 
    (next 1 (+ cur next))) ;declares next, initially 1, then the sum of (the old) cur and next 
    ((= 10 n) ;end condition (ends when n = 10) 
    cur) ; return value 
    ;empty body 
) 

traduciendo el código c-como

for(n=0, cur=0, next=1 ; 
    !(n == 10) ; 
    n=old_n+1, cur=old_next, next = old_cur + old_next) 
{ 
    //do nothing 
    old_n = n; 
    old_cur = cur; 
    old_next = next; 
} 
return cur; 

por cierto debe ser capaz de ver que este código devuelve el número de Fibonacci 10a


EBNF Opcional sintaxis/formales:

La sintaxis según el Hyperspec es:

(do ({var | (var [init-form [step-form]])}*) 
    (end-test-form result-form*) 
    declaration* 
    {tag | statement}*) 

Entender esto requiere conocimiento de EBNF y grandes trozos de la hyperspec

+1

¡excelente idea para mostrar la traducción C, usando 'old_' vars para simular la asignación paralela!Solo para elegir: su código Lisp está mal alineado y tiene un paréntesis de cierre adicional; a su código C le falta el punto y coma final. :) –

+0

Mirando esta traducción, ¿es correcto decir que hacer macro es más como una programación imperativa, en lugar de una programación funcional? –

+1

@hyh sí y no --- el ceceo común es multi-paradigma, y ​​este es un constructo iterativo que actualiza variables, lo cual es ciertamente imperativo. Sin embargo, este formulario devuelve un valor, por lo que podría usar este bucle como un valor de retorno o como una condición en la instrucción if (es decir '(if (> (this-fib-loop) 10) 'gt-10' lte-10) ') que es más funcional – tobyodavies

0
(do ((n 0 (1+ n)) 
    (cur 0 next) 
    (next 1 (+ cur next))) 
    ((= 10 n) cur)) 

hacerlo tiene 3 partes.

  1. variable de
  2. terminar condición
  3. cuerpo

En este ejemplo particular no hay ningún cuerpo. Todo el trabajo real realizado por 1. y 2. Primero configura 3 vars y da el valor inicial y la forma del paso. P.ej. n establece en 0 y durante cada iteración etapas adicionales: (1+ n) que incrementará el n

La condición terminan es ((= n 10) cur): cuando n igual a 10. A continuación, devolver el cur como a toda el valor de retorno de esta do expresión.

combinar todos estos, en este do ejemplo, se hará una recapitulación de 1 a 10, que produce 55

+2

es' result-form-n' not 'action-n' también su segundo bloque de código está mal indentado. – tobyodavies

+1

perdiste muchos paréntesis allí. Además, esto calcula la secuencia '(cur, next) = (0,1) (1,1) (1,2) (2,3) (3,5) (5,8) (8,13) .. .' de números de Fibonacci, no solo suma parcial. –

+0

@tobyodavies tienes razón. mi error. – juanitofatas