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

Đây là một ví dụ từ sách giáo khoa Lisp về từ khóa "làm"Hiểu Common Lisp làm cú pháp vĩ mô

là "làm" mẫu cơ bản là:

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

Nhưng, ví dụ này, nó không rõ với tôi phần nào. Và cũng có thể, những gì làm trung tuyến 2 dòng làm gì?

Cảm ơn bạn!

+3

AFAIR, "do" là macro. – zvrba

Trả lời

8

thụt đầu dòng tốt của bạn rõ ràng cho thấy phần nào là đó:

(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, họ xếp hàng độc đáo, và vật liệu bên trong được thụt vào:

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

do không có đối số thứ ba ở đó: không có phần thân câu lệnh (vòng trống).

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 
) 

dịch vào c-như mã

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; 

tình cờ bạn sẽ có thể thấy rằng mã này trả về số Fibonacci 10


Tùy chọn EBNF/cú pháp chính thức:

Cú pháp theo số Hyperspec là:

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

Hiểu được điều này đòi hỏi phải có kiến ​​thức về EBNF và khối lớn của các Hyperspec

+1

ý tưởng tuyệt vời để hiển thị bản dịch C, sử dụng 'old_' vars để mô phỏng phép gán song song!Chỉ cần chọn gọn gàng: mã Lisp của bạn bị sai lệch và có thêm một dấu ngoặc đơn; mã C của bạn thiếu dấu chấm phẩy kết thúc. :) –

+0

Nhìn vào bản dịch này, có đúng khi nói macro làm giống như lập trình bắt buộc hơn, thay vì lập trình hàm? –

+1

@hyh có và không --- lisp phổ biến là đa mô hình, và đây là một cấu trúc lặp đi lặp lại cập nhật các biến, mà chắc chắn là bắt buộc. Tuy nhiên, biểu mẫu này trả về một giá trị, vì vậy bạn có thể sử dụng vòng lặp này làm giá trị trả về hoặc điều kiện trong câu lệnh if (nghĩa là '(if (> (vòng lặp fib-loop) 10) 'gt-10' lte-10) ') đó là chức năng hơn – tobyodavies

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

làm có 3 phần.

  1. biến
  2. chấm dứt tình trạng
  3. cơ thể

Trong ví dụ cụ này không có cơ thể. Tất cả các công việc thực tế được thực hiện bởi 1. và 2. Đầu tiên nó thiết lập 3 lọ và đưa ra giá trị ban đầu và hình thức bước. Ví dụ. n đặt thành 0 và trong mỗi lần lặp nó bước xa hơn: (1+ n) mà sẽ tăng khi n

Điều kiện chấm dứt là ((= n 10) cur): khi n bằng 10. Sau đó trả lại cur là giá trị toàn bộ trở lại của biểu do này.

Kết hợp tất cả các, trong do ví dụ này nó sẽ tổng hợp từ 1 đến 10 trong đó sản lượng 55

+2

đó là' kết quả-form-n' không 'hành động-n' cũng khối mã thứ hai của bạn là thụt lề nặng. – tobyodavies

+1

bạn đã bỏ lỡ nhiều dấu ngoặc đơn ở đó. Ngoài ra, điều này tính toán trình tự '(cur, next) = (0,1) (1,1) (1,2) (2,3) (3,5) (5,8) (8,13) .. .' của các số Fibonacci, không chỉ là một phần tổng. –

+0

@tobyodavies bạn nói đúng. lỗi của tôi. – juanitofatas