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

Questo è un esempio da manuale di Lisp su parola chiave "fare"Capire Common Lisp fare sintassi macro

il "fare" modello di base è:

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

Ma, per questo esempio, è non mi è chiaro quale parte è quale. E anche, cosa fanno le 2 linee centrali?

Grazie!

+3

AFAIR, "do" è una macro. – zvrba

risposta

8

La vostra buona indentazione mostra quale parte è che chiaramente:

(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 

sguardo, si allineano bene, e il materiale interno è rientrato:

((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. 

tuo do non ha un terzo argomento c'è: non c'è il corpo di s tatements (ciclo vuoto).

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 
) 

tradurre in c-come il codice

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; 

per inciso si dovrebbe essere in grado di vedere che questo codice restituisce il numero di Fibonacci 10


EBNF opzionale/sintassi formale:

La sintassi secondo lo Hyperspec è:

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

Capire questo richiede la conoscenza di EBNF e grandi blocchi del Hyperspec

+1

ottima idea per mostrare la traduzione in C, usando 'old_' vars per simulare l'assegnazione parallela!Solo per selezionare bene: il codice Lisp è allineato in modo errato e ha una parentesi di chiusura aggiuntiva; il tuo codice C manca il punto e virgola finale. :) –

+0

Guardando questa traduzione, è giusto dire che la macro do è più simile alla programmazione imperativa, invece della programmazione funzionale? –

+1

@hyh sì e no --- common lisp è multi-paradigma e questo è un costrutto iterativo che aggiorna le variabili, che è sicuramente un imperativo. Tuttavia questo modulo restituisce un valore, quindi puoi usare questo ciclo come valore di ritorno, o come condizione in in if statement (cioè '(if (> (this-fib-loop) 10) 'gt-10' lte-10) ') che è più funzionale – tobyodavies

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

fare ha 3 parti.

  1. variabile
  2. terminare condizione
  3. corpo

In questo esempio particolare non c'è nessun corpo. Tutto il lavoro reale svolto da 1. e 2. Prima di tutto, imposta 3 vars e fornisce il valore iniziale e la forma del passo. Per esempio. n impostato a 0 e durante ciascuna iterazione ulteriori passi: (1+ n) che incrementerà la n

La condizione di interruzione sia ((= n 10) cur): quando n uguale a 10. Quindi riportare il cur come l'intero valore restituito da questa do espressione.

combinare tutti questi, in questo do esempio si somma da 1 a 10 che produce il 55

+2

è' result-form-n' not 'action-n' anche il tuo secondo blocco di codice è gravemente rientrato. – tobyodavies

+1

hai perso molte parentesi lì. Inoltre, questo calcola la sequenza '(cur, next) = (0,1) (1,1) (1,2) (2,3) (3,5) (5,8) (8,13) .. .' dei numeri di Fibonacci, non solo una somma parziale. –

+0

@tobyodavies hai ragione. colpa mia. – juanitofatas