3

I have a list of interactive functions and want to call a random one of them. In the end I expect to have a function that randomly changes the capitalization of the word at point (without moving the point).

I tried my best but did not get it to work.

The functions

Here are three functions that change the word at point in different ways. (They might behave unexpectedly when point is at the beginning of the word, but we won't worry about that now)

(defun upcase-word-without-moving ()
  "Convert the word at point to uppercase."
  (interactive)
  (save-excursion
    (backward-word)
    (upcase-word 1)
    ))

(defun downcase-word-without-moving ()
  "Convert the word at point to lowercase."
  (interactive)
  (save-excursion
    (backward-word)
    (downcase-word 1)
    ))

(defun capitalize-word-without-moving ()
  "Convert the word at point to be capitalized."
  (interactive)
  (save-excursion
    (backward-word)
    (capitalize-word 1)
    ))

get a random element of a list

(defun random-element-of-list (items)
  (let* ((size (length items))
         (index (random size)))
    (nth index items)))

I tried out this function and it works as expected:

(random-element-of-list '("a" "b" "c"))
(random-element-of-list '('upcase-word-without-moving 'downcase-word-without-moving 'capitalize-word-without-moving))

Put it all together

That should be easy, right? Have a list of the functions, pick a random element of that list and call it as a function.

(defun change-capitalisation-of-word-1 ()
  (interactive)
  (funcall (random-element-of-list '('upcase-word-without-moving 'downcase-word-without-moving 'capitalize-word-without-moving)))
  )

Trying this gives me one of three error messages:

  • Invalid function: 'upcase-word-without-moving
  • Invalid function: 'downcase-word-without-moving
  • Invalid function: 'capitalize-word-without-moving

I don't understand why this is. The emacs-manual on invalid function is a bit heavy on the theory for a lisp-beginner. It also doesn't seem to offer a simple solution.

So I tried changing some things. For example I tried to bind the selected function to a variable:

(defun change-capitalisation-of-word-2 ()
  (interactive)
  (let ((fun-to-call (random-element-of-list '('upcase-word-without-moving 'downcase-word-without-moving 'capitalize-word-without-moving))))
    (funcall fun-to-call)
    )
  )

This code has same problem with the same error messages.

I then tried to leave out the randomness and just use one of the three functions directly.

(defun change-capitalisation-of-word-3 ()
  (interactive)
  (let ((fun-to-call 'upcase-word-without-moving)) ;; constant
    (funcall fun-to-call)
    )
  )

This works as expected (but obviously doesn't solve my problem, it is the random selection of the function that I am after).

So I would like to know:

  • How I can make my function change-capitalisation-of-word work?
  • Is there a fundamental mistake I made or a concept I was not aware of?
1
  • Two years later I have absolutely no idea why I would ever want to call a random function from a list. Past me was up to some crazy stuff and I have no idea what.
    – Kaligule
    Commented Apr 28, 2023 at 7:39

1 Answer 1

3

You have double-quoted your function symbols. The sexp '(symbol1 symbol2) is a list of two symbols: symbol1 and symbol2. The sexp '('symbol1 'symbol2) is a list of two symbols 'symbol1 and 'symbol2. Note that the error message you get, "Invalid function: 'upcase-word-without-moving" tells you that emacs is trying to call the function 'upcase-word-without-moving, not upcase-word-without-moving.

2
  • 1
    Thank you. As always in programming the problem is hard to spot for a beginner and lies in a single letter. I ended up with: ``` (defun change-capitalisation-of-word () (interactive) (funcall (random-element-of-list '(upcase-word-without-moving downcase-word-without-moving capitalize-word-without-moving))) ) ```
    – Kaligule
    Commented Aug 25, 2021 at 13:45
  • The sexp '('symbol1 'symbol2) is a list of two symbols 'symbol1 and 'symbol2. I think this is a bit misleading: ' is a read macro, so 'a expands to (quote a) in the lisp reader (at least conceptually). So the sexp is basically expanded in the lisp reader to (quote ((quote symbol1) (quote symbol2))) and when it passes through the evaluator, the result is ((quote symbol1) (quote symbol2)) - so it is really a list of two lists. This is perhaps nitpicking, but people get confused with quoting exactly because they don't mentally do the expansion.
    – NickD
    Commented Feb 22, 2022 at 17:09

Your Answer

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

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