0

How can I write a generic function that takes feature-specific functions (exec-fun1, exec-fun2) as arguments and invokes them as needed, so I can avoid duplicating control logic for different purposes?

Possibly, exec-fun1 and exec-fun2 could also take arguments themselves.

(defun generic-controlfun (action exec-fun1 exec-fun2) (catch 'exit (dolist (actm actm-seqr) (pcase actm ('armg (exec-fun1) ('go (exec-fun2) (_ (message " Unrecognised argument: %s" actm)) ))) ) 

I wauld them bake my specific function, which internally calls the functions with the appropriate arguments

(defun myspec-fun (actm-seqr) (generic-controlfun (actm-seqr (exec-fun1 args) (exec-fun2 args)) ) 
4
  • 1
    I think you’ve asked this question before, under a different user name; what’s different about this one? Why do you need a dispatcher? Why not just require the library you want to require, or run the initialization code you want to run? What are these intermediate steps supposed to accomplish? Commented Jul 23 at 12:06
  • It makes it easier for me to specify whether to execute something or not. During debugging, I do not need to comment out code. Still, the question is a general one. How can one make a generic function that takes as arguments functions specific to certain features and run them. Commented Jul 23 at 12:13
  • 1
    If you edit your question to remove all of the irrelevant details so that it just asks that question, I will answer it. Commented Jul 23 at 12:30
  • 1
    Is the terminology in this code on account of a non-English preferred language, or is it all custom acronyms and domain-specific terms? kntlr, actm, armg, safg, seqr... it all makes the code unusually difficult to scan. "librorum" I can see is latin, but I presume that's not your first language. If English is actually your first language, I recommend that you try to provide more readable code examples when asking questions. Commented Jul 23 at 13:06

1 Answer 1

1

Emacs Lisp has many different types of values. Any variable can hold a value of any type. Numbers, strings, lists, and even functions are all different types of values.

There are two ways to specify a function as a value, instead of calling the function. The first is by name. Suppose we have this function definition:

(defun db48x/test-func () (* 6 7)) 

Then (db48x/test-func) evaluates to a call, and #'db48x/test-func evaluates to the function itself. This is the form most often recommended for passing functions around. 'db48x/test-func is simply a symbol with no particular meaning, but it can be used to look up the value of the function later, if you want. See chapter 13.7 Anonymous Functions of the GNU Emacs Lisp Reference Manual.

The other way to get a function value is to use an anonymous function, or lambda. See chapter 13.2 Lambda Expressions of the GNU Emacs Lisp Reference Manual. Consider this definition:

(lambda () (* 6 7)) 

This lambda behaves the same way as the previous function, but it is anonymous. It is simply a value that hasn’t been assigned to any name. You can put a lambda anywhere you can put any other type of value, including the argument position of a function call.

Putting both into a single example:

(defun initialize-armg () "this function initializes the armg package" …) (generic-controlfun action #'initialize-armg ; pass in a named function (lambda () ; pass in an anonymous function "this function initializes the go package" …)) 

The only other thing to keep in mind is that Emacs Lisp has two namespaces. Each name can refer either to a variable or to a function, or to both. Which namespace is used depends entirely on which position the name is in. When you have a function call like (a b c), the first element of the list must be a function. It is therefore looked up in the function namespace. The other elements are all assumed to be variables, and are looked up in the variable namespace. See chapter 10.2.5 Evaluation of Function Forms of the GNU Emacs Lisp Reference Manual.

Thus you cannot directly call a function that is stored in a variable. Instead there is a helper function called funcall which does the job for you. See chapter 13.5 Calling Functions of the GNU Emacs Lisp Reference Manual.

Here’s how you would use it in your example:

(defun generic-controlfun (action exec-fun1 exec-fun2) (catch 'exit (dolist (actm actm-seqr) (pcase actm ('armg (funcall exec-fun1)) ('go (funcall exec-fun2)) (_ (message " Unrecognised argument: %s" action)))))) 

See how (exec-fun1) became (funcall exec-fun1)? This is because we need to call a function stored in the exec-fun1 variable, not the function named exec-fun1.

2
  • Would the expressions remain (funcall exec-fun1) and (funcall exec-fun2) if the passed functions include their own arguments? Commented Jul 24 at 0:28
  • 1
    No - read the doc string of funcall with C-h f funcall and the Calling Functions link that @db48x posted in his answer. Commented Jul 24 at 1:54

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.