Sử dụng "gỡ lỗi printf"
Bạn có thể để Emacs giúp bạn hiểu bằng cách sửa đổi định nghĩa hàm:
(defun triangle-using-cond (number)
(message (format "called with %d" number))
(cond ((<= number 0) 0)
((= number 1) 1)
((> number 1)
(+ number (triangle-using-cond (1- number))))))
Chỉ cần thêm (message ...)
một nơi nào đó để có một dấu vết được in vào*Messages*
bộ đệm.
Sử dụng Edebug
Đặt điểm bất cứ nơi nào trong định nghĩa hàm và nhấn C-u C-M-x
vào "công cụ" nó. Sau đó đánh giá chức năng, ví dụ bằng cách đặt điểm sau (triangle-using-cond 3)
và nhấn C-x C-e
.
Bây giờ bạn đang ở chế độ Edebug. Nhấn thanh không gian để bước qua chức năng. Các giá trị trung gian của mỗi biểu thức được hiển thị trong vùng echo. Để thoát chế độ Edebug chỉ cần nhấn q
. Để xóa thiết bị, đặt điểm ở bất kỳ đâu trong định nghĩa và nhấn C-M-x
để đánh giá lại định nghĩa.
Sử dụng trình gỡ lỗi Emacs tiêu chuẩn
M-x debug-on-entry triangle-using-cond
, sau đó, khi triangle-using-cond
được gọi, bạn được đặt trong trình gỡ lỗi Emacs (bộ đệm *Backtrace*
).
Bước qua đánh giá bằng cách sử dụng d
(hoặc c
bỏ qua mọi đánh giá không thú vị).
Để xem trạng thái trung gian (giá trị biến, v.v.) bạn có thể sử dụng e
bất cứ lúc nào. Bạn được nhắc nhập sexp để đánh giá và kết quả đánh giá được in.
Trong khi bạn sử dụng trình gỡ lỗi, hãy giữ một bản sao của mã nguồn hiển thị trong một khung khác, để bạn có thể theo dõi những gì đang diễn ra.
Bạn cũng có thể chèn các cuộc gọi rõ ràng để vào trình gỡ lỗi (nhiều hoặc ít điểm dừng) tại các vị trí tùy ý trong mã nguồn. Bạn chèn (debug)
hoặc (debug nil SOME-SEXP-TO-EVALUATE)
. Trong trường hợp sau, khi trình gỡ lỗi được nhập SOME-SEXP-TO-EVALUATE
được đánh giá và kết quả được in. (Hãy nhớ rằng bạn có thể chèn mã đó vào mã nguồn và sử dụng C-M-x
để đánh giá nó, sau đó hoàn tác - bạn không cần lưu tệp đã chỉnh sửa.)
Xem hướng dẫn Elisp, nút Using Debugger
để biết thêm thông tin.
Đệ quy như một vòng lặp
Dù sao, hãy nghĩ về đệ quy như một vòng lặp. Có hai trường hợp chấm dứt được xác định: (<= number 0)
và (= number 1)
. Trong những trường hợp này, hàm trả về một số đơn giản.
Trong trường hợp đệ quy, hàm trả về tổng của số đó và kết quả của hàm với number - 1
. Cuối cùng, hàm sẽ được gọi với một 1
hoặc một số nhỏ hơn hoặc bằng 0.
Do đó, kết quả trường hợp đệ quy là:
(+ number (+ (1- number) (+ (1- (1- number)) ... 1)
Lấy ví dụ (triangle-using-cond 4)
. Hãy tích lũy biểu thức cuối cùng:
trong lần lặp đầu tiên number
là 4
, vì vậy (> number 1)
nhánh được theo sau. Chúng ta bắt đầu xây dựng một biểu thức (+ 4 ...
và gọi hàm với (1- 4)
, tức là (triangle-using-cond 3)
.
bây giờ number
là 3
, và kết quả là (+ 3 (triangle-using-cond 2))
. Biểu thức tổng kết quả là (+ 4 (+ 3 (triangle-using-cond 2)))
.
number
là 2
hiện nay, vì vậy biểu thức là(+ 4 (+ 3 (+ 2 (triangle-using-cond 1))))
number
là 1
bây giờ, và chúng tôi lấy (= number 1)
chi nhánh, kết quả là nhàm chán 1
. Toàn bộ biểu hiện là (+ 4 (+ 3 (+ 2 1)))
. Đánh giá rằng từ trong ra ngoài và bạn nhận được: (+ 4 (+ 3 3))
, (+ 4 6)
, hoặc chỉ 10
.
triangle-using-cond
với đối số là 1 nhỏ hơn bất kể số đó là gì. Các điều kiện đi theo thứ tự a, b, và sau đó c - bất cứ điều gì khớp trước, là nơi buck dừng lại.