Nếu không có bất kỳ ngữ cảnh nào thì điều này rất khó hiểu.
Ví dụ:
(setq list1 (list 1 2 3 4))
Bây giờ chúng ta có một danh sách bốn số. Biến số list1
trỏ đến điểm yếu đầu tiên.
Nếu chúng ta nhìn vào một đảo ngược phá hoại, chúng ta đang nói về một hoạt động có thể thay đổi các tế bào khuyết điểm. Có nhiều cách khác nhau như thế nào danh sách này có thể được đảo ngược.
Ví dụ: chúng tôi có thể lấy các ô khuyết điểm và đảo ngược các ô đó. Ô khuyết điểm đầu tiên là ô cuối cùng. Cdr của ô đó sau đó phải được thay đổi thành NIL
.
CL-USER 52 > (setq list1 (list 1 2 3 4))
(1 2 3 4)
CL-USER 53 > (nreverse list1)
(4 3 2 1)
Bây giờ chúng tôi biến list1
vẫn trỏ tới các tế bào khuyết điểm tương tự, nhưng cdr của nó đã được thay đổi:
CL-USER 54 > list1
(1)
Để đảm bảo rằng các điểm biến vào một danh sách đảo ngược, các lập trình viên sau đó có nhiệm vụ cập nhật biến và đặt nó thành kết quả của hoạt động nreverse
. Người ta cũng có thể bị cám dỗ để khai thác kết quả quan sát được rằng list1
điểm đến điểm cuối cùng.
Trên đây là những gì nhà phát triển Lisp thường mong đợi. Hầu hết việc thực hiện ngược lại dường như hoạt động theo cách đó. Nhưng nó không được chỉ định trong tiêu chuẩn ANSI CL như thế nào nreverse
phải được thực hiện.
Vậy thay vào đó, thay đổi CAR là gì?
Hãy nhìn vào một thực hiện thay thế nreverse
:
(defun nreverse1 (list)
(loop for e across (reverse (coerce list 'vector))
for a on list do
(setf (car a) e))
list)
Trên chức năng cho phép của chuỗi tế bào khuyết điểm còn nguyên vẹn, nhưng thay đổi xe.
CL-USER 56 > (setq list1 (list 1 2 3 4))
(1 2 3 4)
Bây giờ, hãy sử dụng phiên bản mới, nreverse1
.
CL-USER 57 > (nreverse1 list1)
(4 3 2 1)
CL-USER 58 > list1
(4 3 2 1)
Bây giờ bạn thấy sự khác biệt: list1
vẫn trỏ vào toàn bộ danh sách.
Tóm tắt: bạn cần lưu ý rằng có thể triển khai khác nhau nreverse
. Không khai thác các hành vi thông thường, nơi mà một biến sau đó sẽ trỏ đến khuyết điểm cuối cùng. Chỉ cần sử dụng kết quả của nreverse
và mọi thứ đều ổn.
Lưu ý bên: phiên bản thứ hai có thể được sử dụng ở đâu?
Một số triển khai Lisp trên Máy Lisp cho phép một đại diện giống như vectơ nhỏ gọn của danh sách. Nếu trên một thực hiện Lisp như vậy sẽ nreverse một danh sách như vậy, những người triển khai có thể cung cấp một nreverse giống như vector hiệu quả.
Tôi +1 câu trả lời của bạn vì tôi thích cách tiếp cận chi tiết bạn mất, nhưng tôi không chắc chắn nếu bạn trả lời câu hỏi của OP, đó là làm thế nào để đối phó với thực tế là cả 'car' và' cdr' đều có khả năng bị đột biến khi gọi 'nreverse'. –
@ Chris Jester-Young: không cần phải * đối phó * với nó. Chỉ cần không khai thác một hiệu ứng phụ cụ thể của một triển khai cụ thể. Chỉ cần sử dụng kết quả trả về của 'nreverse'. –
Tôi đồng ý, _if_ danh sách bạn đang truy cập không có bí danh. Nếu không, bạn chạy vào tất cả các loại rắc rối. Đề án, đặc biệt, có rất nhiều thủ tục danh sách trả về kết quả được chia sẻ đuôi, đó là một dạng răng cưa. Ví dụ, kết quả của 'append' và' append! '(' Nconc') chia sẻ đuôi với danh sách cuối cùng được đưa ra, do đó, gọi 'reverse!' ('Nreverse') trên đó có thể là vấn đề (nếu danh sách có đuôi -sharing đang được sử dụng ở nơi khác). –