2016-05-18 16 views
5

Loại đệ quy là loại có cơ sở và trường hợp đệ quy của chính nó.Có thể định nghĩa kiểu đệ quy trong Common Lisp không?

Tôi muốn điều này triển khai "danh sách đã nhập", tức là danh sách có đối thủ chỉ cho phép cùng loại phần tử hoặc số không.

tôi đã cố gắng định nghĩa sau đây:

(deftype list-of (a) `(or null 
          (cons ,a (list-of ,a)))) 

Tuy nhiên, điều này báo hiệu một vấn đề ngăn xếp exausted (ít nhất là trên SBCL) do trình biên dịch cố gắng để recurse qua danh sách-of vô thời hạn. Có thể định nghĩa một kiểu dữ liệu như vậy không?

Trả lời

5

Không thể thực hiện được. Các loại bạn xác định với DEFTYPE là "các loại có nguồn gốc". Kiểu dẫn xuất được mở rộng (như macro) thành một bộ định kiểu kiểu "thực", không thể chứa các kiểu có nguồn gốc. Tất cả các tham chiếu đến các kiểu dẫn xuất (chính là kiểu hoặc các kiểu khác) bên trong phần mở rộng cũng được mở rộng. Vì vậy, kiểu đệ quy sẽ đi vào một vòng lặp infite để thử và mở rộng.

Trivial Types cung cấp loại cho danh sách phù hợp, nhưng điều đó không thực sự kiểm tra các loại phần tử mặc dù lấy nó làm đối số. Vì lý do thẩm mỹ mà sẽ là đủ.

(ql:quickload :trivial-types) 
(use-package :trivial-types) 
(typep '("qwe" "asd" "zxc") '(proper-list string)) ;=> T 
(typep '("qwe" "asd" "zxc" 12) '(proper-list string)) ;=> T 

Nếu không, bạn có thể xác định loại kiểm tra xem các phần tử cặp đầu tiên có đúng loại hay không. Điều đó ít nhất sẽ bắt được những vi phạm rõ ràng nhất.

(deftype list-of (a) 
    `(or null (cons ,a (or null (cons ,a (or null (cons ,a list))))))) 
(typep '("asd") '(list-of string)) ;=> T 
(typep '("asd" 12) '(list-of string)) ;=> NIL 
(typep '("asd" "qwe") '(list-of string)) ;=> T 
(typep '("asd" "qwe" 12) '(list-of string)) ;=> NIL 
(typep '("asd" "qwe" "zxc") '(list-of string)) ;=> T 
(typep '("asd" "qwe" "zxc" 12) '(list-of string)) ;=> T 

Nếu bạn muốn nó hoạt động trong danh sách có độ dài bất kỳ, bạn sẽ phải xác định loại cho từng danh sách khác nhau mà bạn cần.

(defun list-of-strings-p (list) 
    (every #'stringp list)) 
(deftype list-of-strings() 
    `(or null (satisfies list-of-strings-p))) 
(typep '("qwe" "asd" "zxc" "rty" "fgh") 'list-of-strings) ;=> T 
(typep '("qwe" "asd" "zxc" "rty" "fgh" 12) 'list-of-strings) ;=> NIL 
+1

Có vẻ như không hữu ích khi đặt loại vì lý do thẩm mỹ. Vì lý do thẩm mỹ, tôi luôn có thể '(deftype bất cứ điều gì (a) t)', có thể không? – ssice

+0

@ssice Sử dụng '(chuỗi danh sách thích hợp)' không kiểm tra xem danh sách đó có phải là danh sách thích hợp hay không và nó cho mọi người biết mã mà bạn mong đợi nó chứa chuỗi. Rõ ràng mã của bạn không thể dựa vào nó thực sự chứa các chuỗi, nhưng nếu nó không quan trọng thì tốt hơn là không có gì. – jkiiski

+0

Được rồi, đó là một sự thỏa hiệp. Vì vậy, nó là "tốt" cho mã tự viết và nói những sai lầm đơn giản, mà không sâu hơn vào toán học đằng sau các loại HM. – ssice

3

Có, nhưng tôi đã lừa dối;)

(defun satisfication (a) 
    (if a 
     (and (integerp (car a)) 
     (satisfication (cdr a))) 
     T)) 

(deftype my-list() `(satisfies satisfication)) 


(typep (cons 1 (cons 2 (cons 3 nil))) 'my-list) 
> T 


(typep (cons 1 (cons 2 (cons 3.2 nil))) 'my-list) 
> NIL 

Rõ ràng SBCL không thích loại đệ quy - lý do được giải thích cũng bằng câu trả lời khác. Nhưng nếu bạn muốn gắn bó với tiêu chuẩn và vẫn định nghĩa các kiểu đệ quy thì có một ánh sáng ở cuối đường hầm: bạn có thể định nghĩa bất kỳ chức năng nào để kiểm tra sự hài lòng.

+2

Bạn có thể sử dụng '(mọi # 'danh sách số nguyên)'. Bạn cũng có thể xử lý kiểu theo cách chung và sử dụng vòng lặp: '(vòng lặp cho e trong danh sách luôn luôn (typep e type))' – coredump

+1

Tất nhiên, thật dễ dàng "" để viết một hàm để kiểm tra nó với các kiểu đơn lẻ, nhưng vấn đề ploymorphic thú vị hơn nhiều. – ssice

+0

Tôi nghĩ rằng caveat có liên quan nhất với các loại đa hình là bạn không còn có thể định nghĩa một hàm 'satisfies' chỉ lấy một tham số. – ssice

Các vấn đề liên quan