At some point, Emacs added the pure
symbol property, indicating which functions are known to be pure (see here). Is there a way to use this property to determine if an entire expression is constant and side-effect-free? For example, it's pretty easy to determine that (car '(1 2 3))
is a constant expression, since car
is a pure function (i.e. (get 'car 'pure)
returns t) and '(1 2 3)
is a quoted form. However, there are more complex expressions, e.g. involving special forms, which are still constant:
(let ((a (+ 1 2))
(b (- 5 5)))
(if (> b 0)
a
(- a)))
Notably, neither let
nor if
is marked as pure, but this is still a constant expression evaluating to -3.
Is there any way I can take an arbitrary expression and determine whether it is constant? I know there is unsafep
, which appears to implement the necessary expression tree walking, but it is evaluating a different criterion than "constant", so I can't use it directly.
- It's fine to assume that none of the definitions of standard Elisp functions, macros, or special forms (
car
,let
,if
, etc.) have been modified. - For my purposes, "constant" is defined using
equal
. So a function that returns a new list on each call with the same contents every time would be considered constant. - I know there are some constant expressions that involve impure functions, e.g.
(nreverse '(1 2 3))
. I don't mind if the algorithm misses such expressions.
In case it matters, the reason I want to do this is that I'm implementing an elisp macro where constant expressions occurring in a certain context are syntactically valid, but their return value will be ignored, making them pointless, and likely the result of a programmer misunderstanding. So I want to issue a warning if the macro sees a constant expression in this context.