2009-02-23 41 views
18

Tôi đang cố gắng tìm hiểu một số Lisp (Common Lisp) gần đây, và tôi tự hỏi nếu có một cách để cung cấp cho số liên tục một tên giống như bạn có thể làm trong C thông qua enums.Common Lisp tương đương với C enums

Tôi không cần tính năng đầy đủ của enums. Cuối cùng tôi chỉ muốn có mã số có thể đọc được nhanh chóng.

Tôi đã thử các hình cầu và các chức năng nhỏ, nhưng luôn đi kèm với sự suy giảm hiệu suất. Chỉ cần cắm các số vào mã luôn nhanh hơn.

Trả lời

22

Cách thông thường để làm enumerations trong Lisp là sử dụng những biểu tượng . Các ký hiệu nhận được tập trung (thay thế bằng con trỏ đến các mục nhập của chúng trong một bảng biểu tượng) để chúng nhanh như các số nguyên và có thể đọc được dưới dạng các hằng số được liệt kê trong các ngôn ngữ khác.

Vì vậy, nơi trong C bạn có thể viết:

 
enum { 
    apple, 
    orange, 
    banana, 
}; 

Trong Lisp bạn chỉ có thể sử dụng 'apple, 'orange'banana trực tiếp.

Nếu bạn cần một liệt kê loại, sau đó bạn có thể định nghĩa một với deftype:

(deftype fruit() '(member apple orange banana))

và sau đó bạn có thể sử dụng các loại fruit trong declare, typep, typecase và như vậy, và bạn có thể viết các hàm tổng quát chuyên về loại.

+4

Có, nhưng sử dụng từ khóa tốt hơn. – kmkaplan

+0

Đó là một điểm tốt: bằng cách sử dụng từ khóa bạn tránh phải lo lắng về những gói biểu tượng của bạn. –

+0

Thực ra, các hàm chung chỉ có thể chuyên về các lớp, không phải kiểu tùy ý. –

6

Enums là dư thừa cho Lisp, lý do là tất cả những biểu tượng là bản sắc riêng của họ, vì vậy bạn chỉ có thể sử dụng những ví dụ:

[[email protected]:~]$ clisp -q 
[1]> (setf x 'some) ;' 
SOME 
[2]> (eq x 'some) ;' 
T 
[3]> 
15

Ví dụ bạn muốn đặt tên cỡ chữ:

(defconstant +large+ 3) 
(defconstant +medium+ 2) 
(defconstant +small+ 1) 

Bạn có thể viết một macro để làm cho điều đó ngắn hơn.

Định nghĩa liên tục trên thường được viết CHỈ khi các số này cần được chuyển đến một số mã không phải Lisp bên ngoài.

Nếu không, người dùng sẽ chỉ sử dụng các ký hiệu từ khóa:: lớn,: trung bình và: nhỏ.

Bạn có thể kiểm tra chúng bằng EQ và mọi thứ sử dụng một số thử nghiệm để bình đẳng.

(let ((size :medium)) 
    (ecase size 
    (:small ...) 
    (:medium ...) 
    (:large ...))) 

Bạn cũng có thể viết phương pháp cho nó:

(defmethod draw-string (message x y (size (eql :large))) ...) 

Như đã đề cập, bạn có thể định nghĩa một kiểu thiết lập:

(deftype size() '(member :small :medium :large)) 

Sau đó, bạn có thể kiểm tra nếu một cái gì đó là một trong những người:

(let ((my-size :medium)) 
    (check-type my-size size)) 

Phía trên sẽ báo hiệu lỗi nếu kích thước của tôi không phải là một trong số: nhỏ, trung bình hoặc lớn.

Bạn cũng có thể sử dụng các loại trong một hình thức defclass:

(defclass vehicle() 
    ((width :type size :initarg :width))) 

Bây giờ bạn sẽ tạo các đối tượng như ở đây:

(make-instance 'vehicle :width :large) 

Một số triển khai Common Lisp sẽ kiểm tra khi bạn thiết lập các khe đối với một số giá trị bất hợp pháp.

Nếu bây giờ bạn tạo các đối tượng của xe hạng, các vị trí sẽ là một trong số: lớn, trung bình hoặc nhỏ. Nếu bạn nhìn vào đối tượng trong trình gỡ lỗi, thanh tra hoặc một số công cụ khác, bạn sẽ thấy các tên biểu tượng và không phải là 1, 2 hoặc 3 (hoặc bất kỳ giá trị nào bạn thường sử dụng).

Đây là một phần của phong cách Lisp: sử dụng tên biểu tượng khi có thể. Chỉ sử dụng các ký hiệu có giá trị số trong mã giao diện cho các chức năng nước ngoài (như gọi mã C bên ngoài sử dụng enums).

+1

Hằng số số (trái ngược với từ khoá) cũng có thể hữu ích nếu bạn muốn giữ các mảng lớn của sự vật, như trong một mô hình thế giới cho một trò chơi hoặc mô phỏng. "Bản đồ chiếm dụng" của bạn, sau đó, có thể theo dõi gọn gàng và hiệu quả các loại vật khác nhau như tường và quái vật và kho báu. Khoảng thời gian của hằng số có thể được sử dụng để phân loại các thực thể, như trong '(defun monster-p (x) (và (> = x + ít nhất-monster-number +) (<= x + lớn nhất-monster-number +)))' –

+0

Given các cuộc gọi 'defconstant' ở trên, trộn lẫn với các ví dụ sau này bằng cách sử dụng từ khóa, nó tấn công tôi rằng một trong hai có thể kết hợp hai thứ này giống như sau khi một hàm chuyển sang mã không phải là lisp:' (defun size-number) (thesize) (loại kiểm tra kích thước) (trường hợp (: nhỏ + nhỏ +) (: phương tiện + trung bình +) (: lớn + lớn +))) '. Hoặc có thể bỏ qua 'check-type' và sử dụng' ecase' thay vì 'case'. Một 'số-to-size' đối ứng có thể được viết tương tự. – lindes

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