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?
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?
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.
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.
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)
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.
Use defconstant:
(defconstant name initial-value-form [ documentation-string ])
For example:
(defconstant myvar 5)
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)))
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))))
© 2022 - 2024 — McMap. All rights reserved.