【问题标题】:How to define constant like this in lisp?如何在 lisp 中定义这样的常量?
【发布时间】:2012-06-07 21:47:51
【问题描述】:

在python中可以做到这一点

EMPTY, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING, BPAWN = range(8)

你会如何在 lisp 中做等价?

【问题讨论】:

    标签: python common-lisp


    【解决方案1】:

    我曾经这样做的简单宏:

    (defmacro enum-constants (&rest constants)
     `(progn ,@(mapcar #'(lambda (key value) `(defconstant ,key ,value))
                       constants (loop for i from 0 below (length constants) collecting i))))
    

    【讨论】:

      【解决方案2】:

      可以使用macrolet 来计算设置一堆常量的表单:

      (macrolet ((defenumvalues (&rest names)
                   `(progn
                      ,@(loop for n in names and i from 0
                              collect `(defconstant ,n ,i))
                      (values))))
        (defenumvalues empty pawn knight bishop rook queen king bpawn))
      

      替代方案:使用defmacro 编写全局宏。

      使用宏(本地或全局)定义一堆常量的一般优势:编译器展开表达式,然后看到一堆cl:defconstant 形式。

      【讨论】:

      • 为什么要创建另一个答案而不是编辑您自己现有的答案?
      • @sds:macrolet 的不同方法。
      【解决方案3】:

      在 Lisp 中只使用符号会更惯用。通常作为自我评估的关键字符号:

      (defparameter *chess-pieces*
        '(:EMPTY :PAWN :KNIGHT :BISHOP :ROOK :QUEEN :KING :BPAWN))
      

      定义数值是有原因的——有时。尤其是当您需要与外国功能交谈时。在 Lisp 中,你会默认使用符号。

      Common Lisp 没有真正的枚举类型。在动态类型语言中使用符号比使用数字变量有一些优势。例如在调试过程中,变量内容更具描述性:

      比较:

      > (setf c4 queen)
      
      > c4
      6
      

      对比

      > (setf c4 :queen)
      
      > c4
      :queen
      

      在后一个示例中,符号值是自描述的。

      【讨论】:

      • 我不能使用符号,因为我需要稍后将片段信息编码为“移动”变量的一部分。我想我只会使用 defconstant :)
      • 这还不能解释为什么你不能只使用符号?
      【解决方案4】:

      这是一种方法:

      (let ((c 0))
        (dolist (piece '(EMPTY PAWN KNIGHT BISHOP ROOK QUEEN KING BPAWN))
          (eval `(defconstant ,piece ,c)) 
          (incf c)))
      

      【讨论】:

        【解决方案5】:

        假设您已经在某处 ((defun range (n) (loop :for i :from 0 :below n :collect i))) 定义了便捷函数 range,您可以像这样设置一些本地值:

        (destructuring-bind (EMPTY PAWN KNIGHT BISHOP ROOK QUEEN KING BPAWN)
            (range 8)
          #| do stuff |#)
        

        然而,像这样的枚举很少在 Lisp 代码中使用,因为关键字(或其他符号)提供了类似的功能。

        【讨论】:

          【解决方案6】:

          写一个宏来做这件事怎么样?一个例子:

          (defmacro defenum (&rest args)
            (let ((counter 0))
              `(progn
                 ,@(mapcar (lambda (arg)
                             (cond ((symbolp arg)
                                    (prog1
                                        `(defparameter ,arg ,counter)
                                      (incf counter)))
                                   ((listp arg)
                                    (prog1
                                        `(defparameter ,(first arg) ,(second arg))
                                      (setf counter (1+ (second arg)))))
                                   (t (error "broken defenum"))))
                           args))))
          

          使用示例:

          (defenum x (y 2) z)
          
          (defenum EMPTY PAWN KNIGHT BISHOP ROOK QUEEN KING BPAWN)
          

          (在这个例子上可能很容易改进 :-) - 我更喜欢 defparameterdefconstant 所以你可能想要改变)

          【讨论】:

            【解决方案7】:

            使用默认常量:

             (defconstant name initial-value-form [ documentation-string ])
            

            例如:

            (defconstant myvar 5)
            

            【讨论】:

            • 我知道defconstant,我想知道如何一次定义一个常量列表
            猜你喜欢
            • 2018-03-17
            • 1970-01-01
            • 2019-06-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-19
            • 2021-01-07
            • 1970-01-01
            相关资源
            最近更新 更多