Tam giác đệ quy LISP
Lời gọi đệ quy của tôi dường như không hoạt động, tôi đang cố gắng tạo một tam giác cho một số nguyên và với sự giúp đỡ của các bạn, cuối cùng tôi đã có thể làm cho chuỗi in trên cùng một dòng, số lần chính xác cho 1 dòng. Khi kết thúc việc in dòng, tôi có một lệnh gọi đệ quy gọi tới hình tam giác để tạo một dòng khác, một ký tự ngắn hơn. Cuộc gọi này dường như không bao giờ liên lạc được vì một số lý do. Vui lòng tìm mã bên dưới, cảm ơn tất cả các bạn trước vì bất kỳ và tất cả sự giúp đỡ, tất cả đều được đánh giá rất cao!
Lưu ý: Có cách nào để dừng một hàm trong Lisp tương tự như câu lệnh return không? Tôi muốn đệ quy dừng lại ở k = 1, và không tiếp tục đến k = 0.
(defun newTriangle (k)
(cond ((<= k 0) (princ '(Nope)))
((or (= k 1) (= k -1)) (princ 'a))
((> k 0) (make-string k :initial-element #\a))
(newTriangle (- k 1))))
(print (newTriangle 3))
tam giác đầu ra mẫu (3)
aaa
aa
a
tam giác đầu ra mẫu (-3)
aaa
aa
a
Trả lời
Đầu tiên, bạn cần quyết định chính xác nó newTriangleđang làm gì. Cuộc gọi (print (newTriangle 3))gợi ý rằng newTrianglesẽ trả về một chuỗi , sau đó được in ra bởi lệnh gọi tới print. Tuy nhiên, định nghĩa OP newTrianglelà cả đầu ra in và trả về một dòng duy nhất của tam giác dưới dạng một chuỗi.
Lệnh gọi đệ quy tới newTrianglekhông bao giờ đạt được vì tất cả các trường hợp có thể xảy ra đối với giá trị của kđều hết trước khi đạt đến dòng này. Vì kchỉ có thể nhỏ hơn 0, bằng 0 hoặc lớn hơn 0, và vì tất cả các trường hợp này đều được kiểm tra trước khi đạt được lệnh gọi đệ quy, nên nó không bao giờ đạt được. Cũng lưu ý rằng mã OP có sai cú pháp đối với phần cuối cùng của condcâu lệnh. Biểu thức đầu tiên trong một condnhánh là một phép thử và quy ước là sử dụng tở đây cho một nhánh sẽ luôn được đánh giá nếu đạt. Nhưng, nhiều trường hợp này không cần thiết ở đây.
Giả sử newTrianglehàm không trả về một chuỗi, nhưng in ra một hình tam giác như một hiệu ứng phụ , thì nó phải làm gì? Nếu số đầu vào lớn hơn 0, nó nên in ra một dòng có số ký tự bằng số đầu vào và sau đó gọi chính nó với đầu vào giảm đi một; nếu không nó sẽ không làm gì cả:
(defun print-triangle (k)
(when (> k 0)
(princ (make-string k :initial-element #\a))
(terpri)
(print-triangle (- k 1))))
Định nghĩa này được đặt tên print-triangleđể nhấn mạnh rằng nó in ra một hình tam giác như một hiệu ứng phụ và bởi vì kebab-case là thành ngữ trong Lisps, còn camelCase thì không. Lưu ý rằng mỗi lần print-triangleđược gọi với đầu vào lớn hơn 0, một chuỗi có độ dài chính xác sẽ được in và sau đó một dòng mới được in (với tên không rõ ràng terpri, chỉ ghi một dòng mới vào dòng đầu ra hiện tại), trước khi gọi print-trianglelại với kgiảm 1.
Tương tác REPL mẫu:
CL-USER> (print-triangle 3)
aaa
aa
a
NIL
Nếu mục tiêu là trả về một chuỗi thay vào đó , một cách tiếp cận sẽ là gọi một hàm trợ giúp giữ kết quả trong một tham số:
(defun new-triangle (k)
(build-triangle k ""))
(defun build-triangle (k result)
(if (> k 0)
(build-triangle (- k 1)
(concatenate 'string
result
(make-string k :initial-element #\a)
(string #\newline)))
result))
Ở đây, new-trianglenhận một đối số số nguyên và gọi build-triangle, truyền cả đối số số nguyên và một chuỗi trống vào resultvị trí. Các build-trianglechức năng hoạt động cũng tương tự như print-triangletrước đây, nhưng thay vì in dòng, họ được nối với result, cùng với một chuỗi chứa một dòng mới. Khi build-trianglekết thúc, resultchuỗi được trả về new-triangle. Lưu ý rằng chỉ cần gọi new-triangletừ REPL sẽ in ra chuỗi kết quả dưới dạng dữ liệu (nghĩa là với dấu ngoặc kép); gọi printkết quả của new-trianglecả hai sẽ in chuỗi dưới dạng dữ liệu và trả về chuỗi. Để xem chuỗi được in mà không có dấu ngoặc kép, formatcó thể được sử dụng; hoặc bạn có thể sử dụng princđể in chuỗi không có dấu ngoặc kép và trả về chính chuỗi:
CL-USER> (new-triangle 3)
"aaa
aa
a
"
CL-USER> (print (new-triangle 3))
"aaa
aa
a
"
"aaa
aa
a
"
CL-USER> (format t "~A" (new-triangle 3))
aaa
aa
a
NIL
CL-USER> (princ (new-triangle 3))
aaa
aa
a
"aaa
aa
a
"