I'm trying to do some processing of values passed in a plist. Processing is quite similar: get a value, convert it to number if necessary, check if within bounds and if yes, return a string with that number, properly formatted.

Thus, I decided to create a list of actions, and then map through them, picking up non-nil values:

(defun knl--initialize-numerics (info)
  "Makes a string containing initialization of numerical parameters"
  ;; logic is: convert to number, if satisfies condition print it, skip otherwise
  (let* ((num-inits '((:knl-width 'identity (-partial '> 0) "%d")
                      (:knl-height 'identity (-partial '> 0) "%d")
                      (:knl-margin 'string-to-number (-partial '>= 0) "%.2f")
                      (:knl-min-scale 'string-to-number (-partial '> 0) "%.2f")
                      (:knl-max-scale 'string-to-number (-partial '> 0) "%.2f"))))
     ;; function
     (-when-let* (((sym conv cond frm) it)
                  (oval (plist-get info sym))
                  (val (funcall conv oval))
                  (matches? (funcall cond val))
                  (name (s-lower-camel-case (s-chop-prefix ":knl-" (symbol-name sym))))
                  (formatted (format frm val)))
     ;; data

The above code fails at (val (funcall conv oval)) in ielm when I try to execute the following:

ELISP> (knl--initialize-numerics '(:knl-width 10 :knl-height 0 :knl-margin 0))
*** Eval error ***  Invalid function: (quote identity)

I was trying the same with a simple function, and it works:

ELISP> (let ((conv 'identity) (val 5)) (funcall conv val ))
5 (#o5, #x5, ?\C-e)

Why doesn't it then work in a more complex example? Is that because of some dash.el magic?

  • The IELM error has knl--reveal-initialize-numerics but you show code for knl--initialize-numerics - is this a typo, or had you probably confused these two functions?
    – wvxvw
    Nov 27 '16 at 10:02
  • Quoting inside a quoted list is a classic beginner's mistake, remove the inner quotes and everything should work again.
    – wasamasa
    Nov 27 '16 at 10:09
  • @wvxvw sorry, it was a typo, I wanted to make everything shorter so I removed most of prefixes Nov 27 '16 at 10:14
  • You probably want to use < in those tests.
    – politza
    Nov 27 '16 at 10:30
  • @politza Thanks, you're right. I've changed code to use -rpartial Nov 27 '16 at 21:31

There seems to be a fair bit of confusion how quoting works. In Lisp, symbols and lists fulfill a dual meaning, depending on whether they're quoted or not:

  • Unquoted symbol: Evaluate the symbol (by looking up its value in the current environment)
  • Quoted symbol: Do not evaluate the symbol (by returning the symbol)
  • Unquoted list: Evaluate the function (by applying its first item to the remaining items)
  • Quoted list: Do not evaluate the list (by returning the list as is)

The last case is particularly important as the quoting applies to everything inside the list. '(x y z) evaluates to (x y z), the symbols inside the list are not evaluated. Therefore, '(x 'y z) would evaluate to (x (quote y) z) which is most certainly not what one would want.

Sometimes you'll want to selectively evaluate parts of a quoted list. The hard way is to construct the list manually from quoted and not quoted symbols, the easier way is to use the backquote and unquote mechanism to specify what to evaluate in the list. Assuming y has the value 42 in the environment, both (list 'x y 'z) and `(x ,y z) evaluate to (x 42 z).

Armed with this knowledge, the alist in your example should look like the following:

`((:knl-width identity ,(-partial '> 0) "%d")
  (:knl-height identity ,(-partial '> 0) "%d")
  (:knl-margin string-to-number ,(-partial '>= 0) "%.2f")
  (:knl-min-scale string-to-number ,(-partial '> 0) "%.2f")
  (:knl-max-scale string-to-number ,(-partial '> 0) "%.2f"))
  • Should be (list 'x y 'z) I guess.
    – mutbuerger
    Nov 27 '16 at 12:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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