-2

The following function is intended to ensure that a variable defined in a defvar is constrained within a numeric range.

I do not want to hardwire the modification of conshine-verbiage, so one can pass any variable and the function will change its value accordingly. Instead of using the value n, I would like to pass a variable, then check its value within the function itself.

(defun conshine-constrain-verbiage (n min-n max-n)
  "Ensure that value of conshine-verbiage is between MIN-N and MAX-N 
inclusive by constraining."

  ;; (eq verbiage nil) and (null verbiage) and equivalent

  (cond
   ((< n min-n)  (setq conshine-verbiage min-n))
   ((> n max-n)  (setq conshine-verbiage max-n))
   ((eq conshine-verbiage t)  (setq conshine-verbiage 1))
   ((eq conshine-verbiage nil)  (setq conshine-verbiage 0))
   (t  (setq conshine-verbiage 0))))

Then I made this attempt

(defun conshine-constrain (var min-n max-n)
  "Ensure that value of var is between MIN-N and MAX-N 
inclusive by constraining."

  (cond
   ((< var min-n)  (setq var min-n))
   ((> var max-n)  (setq var max-n))
   ((eq var t)     (setq var 1))
   ((eq var nil)   (setq var 0))))

But it failed on

(defvar pingu 21)
(conshine-constrain pingu 0 8)
(message "%s" pingu)
3
  • 1
    Pass the variable as a symbol to your function. use symbol-value to get its value to test. Then use set, not setq, to set the variable to whatever new value you want. Consider spending some time with the docs, learning about variables and symbols, as you ask multiple questions that show you're missing some understanding here.
    – Drew
    Aug 21, 2022 at 1:49
  • Rightly so. Got to learn working with symbols.
    – Dilna
    Aug 21, 2022 at 1:53
  • Managed this one (< (symbol-value var) min-n) (set var min-n)). But not these two ((eq (symbol-value var) t) (set var 1)) and ((eq (symbol-value var) nil) (set var 0)).
    – Dilna
    Aug 21, 2022 at 2:04

2 Answers 2

1

Here is a sample:

(defmacro change-var (var)
  `(setq ,var 15))

Try it out:

(defvar foo 12)

(change-var foo)

foo ; => 15
0

It seems evident to me that the skill you need is to be able to read some code and execute it as the interpreter will, as you read it. Learning this is the key to being a good engineer, as it allows you to truly understand the code, rather than just changing things at random until by random chance you get something that works.

The simplest rule we use to understand the evolution of a Lisp process is called the Substitution Rule. The Substitution Rule will get you through 99% of the code you read, so it is ok that it leaves out some minor details; the simplicity is worth it. Let me show you an example.

Suppose someone has just called your function like this: (conshine-constrain-verbiage 42 0.0 1.0) (Perhaps by typing it into the *scratch* buffer and hitting C-x C-e.)

The first thing that happens is that the arguments are each evaluated, but they are of course just numbers so we can skip that step. Next, the values of the arguments are substituted into the body of the function in place of the names of the arguments. This is the result:

(cond
   ((< 42 0.0)  (setq conshine-verbiage 0.0))
   ((> 42 1.0)  (setq conshine-verbiage 1.0))
   ((eq conshine-verbiage t)  (setq conshine-verbiage 1))
   ((eq conshine-verbiage nil)  (setq conshine-verbiage 0))
   (t  (setq conshine-verbiage 0)))

You can see that each occurence of n has been replaced by 42, each min-n by 0.0 and each max-n by 1.0.

The next step is to remember what cond does. cond looks at each pair in turn and evaluates the predicate. If the predicate evaluates to t, it evaluates the consequend, otherwise it goes on to the next pair.

The first predicate evaluates to nil:

(cond
   (nil  (setq conshine-verbiage 0.0))
   ((> 42 1.0)  (setq conshine-verbiage 1.0))
   ((eq conshine-verbiage t)  (setq conshine-verbiage 1))
   ((eq conshine-verbiage nil)  (setq conshine-verbiage 0))
   (t  (setq conshine-verbiage 0)))

So the first consequend will be ignored:

(cond
   ((> 42 1.0)  (setq conshine-verbiage 1.0))
   ((eq conshine-verbiage t)  (setq conshine-verbiage 1))
   ((eq conshine-verbiage nil)  (setq conshine-verbiage 0))
   (t  (setq conshine-verbiage 0)))

The next predicate, however, evaluates to t:

(cond
   (t  (setq conshine-verbiage 1.0))
   ((eq conshine-verbiage t)  (setq conshine-verbiage 1))
   ((eq conshine-verbiage nil)  (setq conshine-verbiage 0))
   (t  (setq conshine-verbiage 0)))

cond throws the rest away, so that the consequend will be evaluated:

(setq conshine-verbiage 1.0)

I recommend watching the lectures from MIT 6.001, Introduction to Computer Science, which covers the Substitution Rule in detail.

I leave it to you to use the Substitution Rule to find the three bugs in your function.

3
  • I understand all that. I do not want to hardwire the modification of conshine-verbiage, but be able to pass any variable and the function will change its value. Instead of using the value n, I would like to pass a variable.
    – Dilna
    Aug 20, 2022 at 23:11
  • 1
    That is not evident in your question. You need to improve the way you ask questions too.
    – db48x
    Aug 20, 2022 at 23:39
  • Fair enough request. At any rate, it would be instructive for others reading.
    – Dilna
    Aug 20, 2022 at 23:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.