0

Q: How can I display this let-bound lambda expression as a symbol -- i.e., display it as my-func instead of (lambda (arg1 ...))?

I'd like the best of both worlds -- i.e., be able to use funcall in one area of the code, yet extract a pretty name my-func from my-list elsewhere in the code.

(let* (
    (my-func
      (lambda (arg1 arg2 arg3)
        (message "arg1: %s | arg2: %s | arg3: %s" arg1 arg2 arg3)))
    (my-list (list my-func '("foo" "bar" "baz"))))
  (apply 'funcall (car my-list) (car (cdr my-list)))
  (message "I want my-func to appear as \"my-func\":  %s" (car my-list)))
lawlist
  • 18,826
  • 5
  • 37
  • 118
  • Is this using lexical binding? Because in that case your variable name `my-func` doesn't even show up in the compiled code at all. – npostavs Feb 07 '17 at 19:41
  • @npostavs -- I would prefer not to use lexical binding at the top of this particular file, but i am open to modifying this snippet to use something like `lexical-let` if that will help achieve the goal. Most of the time, I generally use the back-tick and comma combination instead of `lexical-let`. I will be byte-compiling the code in the future. – lawlist Feb 07 '17 at 20:01

1 Answers1

2

Assuming you are using dynamic binding you can search through the obarray for your value:

;;; Assumes dynamic binding.  This is a macro because a function would
;;; introduce more bound variables that could hide the thing we're
;;; looking for.
(defmacro find-local-val (val)
  (let ((sym-var (make-symbol "sym"))
        (val-var (make-symbol "val")))
    `(catch 'varname
       (let ((,val-var ,val))
         (mapatoms (lambda (,sym-var)
                     (when (and (boundp ,sym-var)
                                (eq (symbol-value ,sym-var) ,val-var))
                       (throw 'varname ,sym-var))))
         (error "Couldn't find a name for %S" ,val-var)))))

(let* ((my-func
        (lambda (arg1 arg2 arg3)
          (message "arg1: %s | arg2: %s | arg3: %s" arg1 arg2 arg3)))
       (my-list (list my-func '("foo" "bar" "baz"))))
  (apply (car my-list) (car (cdr my-list)))
  (message "I want my-func to appear as \"my-func\":  %s"
           (find-local-val (car my-list))))

This won't work if my-func is a lexical variable. Another possibility which always works is to bind with cl-letf and call it by symbol instead of value:

(cl-letf (((symbol-function 'my-func)
           (lambda (arg1 arg2 arg3)
             (message "arg1: %s | arg2: %s | arg3: %s" arg1 arg2 arg3))))
  (let ((my-list (list #'my-func '("foo" "bar" "baz"))))
    (apply (car my-list) (car (cdr my-list)))
    (message "I want my-func to appear as \"my-func\":  %s"
             (car my-list))))
npostavs
  • 9,033
  • 1
  • 21
  • 53