It's unusual to `defun` within a function. If you just want `expat` available while executing `expand-pattern`, you should use use `letrec`: (defun expand-pattern (pattern) (letrec ((expat (lambda (parents expr) (pcase expr ((or (pred stringp) (pred numberp)) (mapcar (lambda (parent) (cons expr parent)) parents)) (`(and ,first) (funcall expat parents first)) (`(and ,first . ,rest) (funcall expat (funcall expat parents first) (cons 'and rest))) (`(or . ,args) (apply #'append (mapcar (lambda (arg) (funcall expat parents arg)) args))) (_ (error "unknown %S" expr)))))) (mapcar (lambda (tokens) (mapconcat (lambda (token) (format "%s" token)) (reverse tokens) "")) (funcall expat '(()) pattern)))) This way, the binding of `expat` doesn't live beyond the function. It looks like what you're doing is a 'reduce' type of operation - you may find it worthwhile to look into `cl-reduce` and related functions.