我最近正在尝试学习一些Lisp(Common Lisp),我想知道是否有一种方法可以为常数提供一个名称,就像你可以通过枚举在C中做的那样。
我不需要枚举的完整功能集。最后,我只想拥有快速的和可读代码。
我已经尝试过全局和小功能,但总会带来性能降低。只需将数字插入代码中总是更快。
答案 0 :(得分:21)
在Lisp中执行枚举的常规方法是使用符号。符号被实现(用符号表中的条目指针替换),因此它们与整数一样快,并且与其他语言中的枚举常量一样可读。
所以在C中你可能会写:
enum { apple, orange, banana, };
在Lisp中,您可以直接使用'apple
,'orange
和'banana
。
如果您需要枚举的类型,那么您可以使用deftype
定义一个:
(deftype fruit () '(member apple orange banana))
然后您可以使用fruit
,declare
,typep
等类型typecase
,等等,,您可以编写专门针对该类型的泛型函数输入
答案 1 :(得分:15)
例如,您想命名字体大小:
(defconstant +large+ 3)
(defconstant +medium+ 2)
(defconstant +small+ 1)
你可以编写一个宏来缩短它。
以上常量定义通常仅在需要将这些数字传递给某些外部非Lisp代码时才会写入。
否则只会使用关键字符号:: large,:medium和:small。
您可以使用EQ和使用某些测试进行相等测试的所有内容来测试它们。
(let ((size :medium))
(ecase size
(:small ...)
(:medium ...)
(:large ...)))
你也可以为它编写方法:
(defmethod draw-string (message x y (size (eql :large))) ...)
如上所述,您可以定义集类型:
(deftype size () '(member :small :medium :large))
然后你可以检查是否有其中任何一个:
(let ((my-size :medium))
(check-type my-size size))
如果my-size不是以下之一,则上面会发出错误:small,:medium或:large。
您还可以使用defclass形式的类型:
(defclass vehicle ()
((width :type size :initarg :width)))
现在你要创建像这样的对象:
(make-instance 'vehicle :width :large)
一些Common Lisp实现将检查何时将插槽设置为某个非法值。
如果您现在创建类车辆的对象,则插槽将是以下之一:large,:medium或:small。如果您在调试器,检查器或其他工具中查看对象,您将看到符号名称而不是1,2或3(或者您通常使用的任何值)。
这是Lisp风格的一部分:尽可能使用符号名称。仅在外部函数的接口代码中使用带数值的符号(例如调用使用枚举的外部C代码)。
答案 2 :(得分:6)
枚举对Lisp来说是多余的,原因是所有符号都是他们自己的身份,所以你可以使用它们,例如:
[dsm@localhost:~]$ clisp -q
[1]> (setf x 'some) ;'
SOME
[2]> (eq x 'some) ;'
T
[3]>