2013-05-17 19 views
8

Tôi đang cố gắng mô phỏng danh sách giống như Lisp trong JavaScript (chỉ là một bài tập không có lý do thực tế), nhưng tôi đang cố gắng tìm ra cách thể hiện tốt nhất một danh sách trống.Có phải danh sách trống trong Lisp được tạo từ một ô lưu trữ không?

Danh sách trống chỉ là giá trị nil hoặc có nằm trong mui xe được lưu trữ trong ô điều khiển không?

Tôi có thể:

(car '()) 
NIL 
(cdr '()) 
NIL 

nhưng một danh sách trống chắc chắn không thể (cons nil nil), bởi vì nó sẽ không thể phân biệt từ một danh sách lưu trữ một đơn nil. Nó sẽ cần phải lưu trữ một số giá trị đặc biệt khác.

Mặt khác, nếu danh sách trống không được xây dựng từ ô điều hướng, có vẻ như không thể có giao diện cấp cao nhất quán để nối một giá trị vào danh sách hiện có. Một chức năng như:

(defun append-value (list value) ... 

Sẽ sửa đổi đối số của nó, nhưng chỉ khi đó không phải là danh sách trống, có vẻ xấu.

+3

Tôi đã chỉnh sửa bài đăng của bạn để sử dụng 'defun' và không phải' define', là từ Đề án. Tôi không nghĩ rằng bạn đang nói về Scheme, vì Scheme không có 'nil', nó không cho phép bạn chuyển vào một danh sách rỗng tới' car' và 'cdr', và việc sử dụng danh sách trực tiếp đột biến được cau mày nhiều hơn trong cộng đồng Đề án. –

+2

cũng có kỹ thuật [* head sentelel *] (http://stackoverflow.com/search?q=user%3A849891+head+sentinel), để sử dụng cá nhân của bạn: bắt đầu với danh sách singleton không trống, nói '(1) 'hoặc bất cứ điều gì; xử lý nó theo cách thống nhất và trả lại 'cdr' của nó ở cuối. Cho phép đơn giản hóa mã tốt đẹp với mức giá của một phân bổ tế bào bổ sung. –

Trả lời

11

Một danh sách trống chỉ đơn giản là biểu tượng nil (và ký hiệu, theo định nghĩa, không phải là khuyết điểm). carcdr được xác định để trả lại nil nếu được cung cấp nil.

Đối với các chức năng đột biến danh sách, chúng trả về một giá trị mà bạn có nghĩa vụ phải gán lại cho biến của bạn. Ví dụ, hãy xem đặc tả cho hàm nreverse: nó có thể sửa đổi danh sách đã cho, hay không, và bạn có nghĩa vụ phải sử dụng giá trị trả về, và không dựa vào nó để sửa đổi tại chỗ.

Ngay cả nconc, hàm hủy phụ thêm tinh túy, hoạt động theo cách đó: giá trị trả về của nó là danh sách được thêm vào mà bạn được cho là sử dụng. Nó được chỉ định để sửa đổi các danh sách đã cho (trừ cái cuối cùng) tại chỗ, nhưng nếu bạn cho nó nil làm đối số đầu tiên, nó không thể sửa đổi tốt, vì vậy bạn vẫn phải sử dụng giá trị trả về.

2

Hãy thử nó với thông dịch Lisp của bạn:

(eq nil '()) 
=> t 

Một số hoạt động là đặc biệt-cased làm unorthogonal (hoặc thậm chí tò mò :-) điều khi hoạt động trên nil/danh sách trống. Hành vi của carcdr bạn đang điều tra là một trong những điều đó.

Tính tiện lợi của nil là danh sách trống là một trong những điều đầu tiên bạn tìm hiểu về Lisp. Tôi đã cố gắng để đạt được một hit Google tốt nhưng tôi sẽ chỉ chọn một vì có quá nhiều: http://www.cs.sfu.ca/CourseCentral/310/pwfong/Lisp/1/tutorial1.html

+0

Vâng, tôi biết về danh tính, nhưng tôi đã tự hỏi về đại diện nội bộ.Vì vậy, nó không thể có một chức năng chắp thêm giá trị với giao diện nhất quán liên quan đến đối số của nó? –

+1

@JanWrobel Như tôi đã đề cập trong câu trả lời của tôi, giao diện của bạn phải trả về giá trị mới, có thể là cùng một danh sách hay không, tùy thuộc vào việc bạn có thể sửa đổi nó tại chỗ hay không. Người gọi nên sử dụng giá trị trả lại, bất kể, chuyển nhượng lại biến của họ nếu cần. –

8

Tin hay không, đây thực sự là câu hỏi tôn giáo.

Có những phương ngữ mà mọi người dám gọi là một số loại Lisp trong đó danh sách trống là conses hoặc các đối tượng tổng hợp của một số loại, chứ không chỉ là một nguyên tử như nil.

Ví dụ: trong danh sách "MatzLisp" (được gọi là Ruby) thực sự là mảng.

Trong NewLisp, danh sách là vùng chứa: đối tượng thuộc loại danh sách chứa danh sách liên kết của các mục, vì vậy danh sách trống là vùng chứa trống.[Reference].

Trong ngôn ngữ Lisp không phải là cụm sao ngoạn mục của loại này, danh sách trống là nguyên tử và danh sách không trống là ô nhị phân có trường giữ mục đầu tiên và trường khác chứa phần còn lại của danh sách. Danh sách có thể chia sẻ hậu tố. Với danh sách như (1 2 3), chúng tôi có thể sử dụng cons để tạo (a 1 2 3)(b c 1 2 3) cả hai đều chia sẻ bộ nhớ cho (1 2 3).

(Trong ANSI thông thường ANSI, danh sách trống nguyên tử () là đối tượng giống như biểu tượng nil, mà tự đánh giá và cũng là sai Boolean. Trong Đề án, () không phải là biểu tượng. Boolean false #f đối tượng. Tuy nhiên, danh sách Đề án vẫn được tạo thành từ các cặp và được kết thúc bởi một nguyên tử.)

Khả năng đánh giá (car nil) không tự động theo dõi từ danh sách khuyết điểm của danh sách và nếu chúng ta nhìn ở tài liệu Lisp cổ đại, chẳng hạn như cẩm nang Lisp 1.5 từ đầu năm 1960 - một điều gì đó, chúng ta sẽ thấy rằng điều này đã vắng mặt. Ban đầu, car thực sự là một cách để truy cập vào một trường của ô khuyết điểm và yêu cầu nghiêm ngặt đối số ô đối lập.

Ý tưởng hay như cho phép (car nil) hoạt động (để tin tặc có thể cắt nhiều dòng mã vô dụng khỏi chương trình của họ) không xuất hiện qua đêm. Ý tưởng cho phép (car nil) có thể đã xuất hiện từ InterLisp. Trong bất kỳ trường hợp nào, Evolution Of Lisp tuyên bố rằng MacLisp (một trong những người tiền nhiệm quan trọng của Common Lisp, không liên quan đến Apple Macintosh đến hai mươi năm sau), bắt chước tính năng này từ InterLisp (một trong những người tiền nhiệm quan trọng).

Các chi tiết nhỏ như thế này tạo nên sự khác biệt giữa lập trình dễ thương và chửi thề ở màn hình: xem ví dụ A Short Ballad Dedicated to the Growth of Programs lấy cảm hứng từ cuộc đấu tranh của lập trình viên Lisp với phương ngữ không rõ ràng trong đó danh sách trống không thể truy cập với car. boolean false.

+0

Tôi không nghĩ mọi người thực sự cố gắng vượt qua Ruby như một Lisp. Có thật không?! Ngoài ra, vui đâm vào Đề án trong đoạn cuối cùng. ;-) –

4

NIL là hơi một con thú lạ trong Common Lisp vì

  • đó là một biểu tượng (nghĩa là symbolp lợi nhuận T)
  • là danh sách
  • KHÔNG một tế bào khuyết điểm (consp lợi nhuận NIL)
  • bạn có thể mất CARCDR của nó anyway

Lưu ý rằng lý do đằng sau điều này có lẽ cũng là lịch sử và bạn không nên nghĩ rằng đây là giải pháp hợp lý duy nhất. Các phương ngữ Lisp khác đã lựa chọn khác nhau.

+0

Và vì danh sách Lisp thường gặp này cũng hơi lạ, bởi vì câu trả lời cho 'là danh sách có thể thay đổi?' là một thời gian nào đó'. –

+2

@JanWrobel Danh sách là một ảo tưởng. Dữ liệu thực tế nằm trong conses và 'nil'. Conses là mutable. 'nil' thì không. Đó là tất cả. –

+0

@ ChrisJester-Young: đồng ý về ảo ảnh; thảo luận về tính đột biến của danh sách trong CL là vô nghĩa vì danh sách không phải là đối tượng. Tuy nhiên nhiều ý tưởng Lisp không cần phải phụ thuộc vào cách tiếp cận này và bạn có thể xây dựng một phương ngữ lisp nơi 'list' là một đối tượng lớp đầu tiên. Ví dụ tôi đã xây dựng một trình biên dịch lisp nhắm mục tiêu javascript sử dụng các đối tượng mảng js để biểu diễn các danh sách (không có 'CAR' và không' CDR' và chia sẻ chỉ có thể ở cấp phần tử chứ không phải ở cấp độ đuôi). Cho đến nay tôi khá hài lòng với giải pháp này. – 6502