How to define constant like this in lisp?
Asked Answered
D

7

3

In python it's possible to do this

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

How would you do equivalent in lisp?

Doubleacting answered 3/6, 2012 at 13:38 Comment(0)
A
11

It would be more idiomatic in Lisp to just use symbols. Typically as self-evaluating keyword symbols:

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

There are reasons to define numeric values - sometimes. Especially when you need to talk to foreign functions. In Lisp you would by default use symbols.

Common Lisp does not have a real enumeration type. Using symbols in a dynamically typed language has some advantages over using numeric variables. For example during debugging the variable contents are more descriptive:

Compare:

> (setf c4 queen)

> c4
6

vs.

> (setf c4 :queen)

> c4
:queen

In the latter example the symbol value is self-descriptive.

Ammo answered 3/6, 2012 at 18:36 Comment(2)
I can't use symbols since I need to encode the piece information as part of "move" variable later on. I guess I'll just use defconstant :)Doubleacting
That still doesn't explain why you can't just use the symbols?Shaffert
T
4

Assuming that you have defined the convenience function range somewhere ((defun range (n) (loop :for i :from 0 :below n :collect i))), you could set up some local values like this:

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

However, enumerations like this are seldomly used in Lisp code, since keywords (or other symbols) provide similar functionality.

Trodden answered 3/6, 2012 at 16:34 Comment(0)
S
2

What about writing a macro to do this? An example:

(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))))

Examples of usage:

(defenum x (y 2) z)

(defenum EMPTY PAWN KNIGHT BISHOP ROOK QUEEN KING BPAWN)

(it's probably very easy to improve on this example :-) - I prefer defparameter to defconstant so that's something you may want to change)

Sling answered 3/6, 2012 at 16:23 Comment(0)
A
1

One can use macrolet to compute a form which sets a bunch of constants:

(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))

Alternative: writing a global macro with defmacro.

The general advantage of using a macro (local or global) to define a bunch of constants: the compiler expands the expression and then sees a bunch of cl:defconstant forms.

Ammo answered 5/5, 2018 at 15:3 Comment(2)
why create another answer instead of editing your own existing one?Walling
@sds: different approach with macrolet.Ammo
R
0

Use defconstant:

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

For example:

(defconstant myvar 5)
Russom answered 3/6, 2012 at 13:42 Comment(1)
I know defconstant, I want to know how I can define a list of constants at onceDoubleacting
K
0

Here's one way to do it:

(let ((c 0))
  (dolist (piece '(EMPTY PAWN KNIGHT BISHOP ROOK QUEEN KING BPAWN))
    (eval `(defconstant ,piece ,c)) 
    (incf c)))
Kitts answered 3/6, 2012 at 23:51 Comment(0)
G
0

Simple macro that I used to do just that:

(defmacro enum-constants (&rest constants)
 `(progn ,@(mapcar #'(lambda (key value) `(defconstant ,key ,value))
                   constants (loop for i from 0 below (length constants) collecting i))))
Gird answered 13/4, 2021 at 12:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.