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.