3

How can I convert a lisp expression to LaTeX math expression.

From simple things like (- 3 2 1) which should be converted to 3 - 2 - 1, to relatively complex things like: (* 1 2 (/ 2 3))1 \times 2 \times \frac{2}{3}, or (somefunc 1 2)somefunc(1,2), and so on.

Even being able to use some variables instead of numbers and convert them would be nice.

I type Lisp expressions in Emacs a lot, because I can just evaluate that there and get the output. That means I don't have to actually run a calculator or a terminal elsewhere. But I'd like to put valid LaTeX math expressions into the reports, and instead of typing again.

Is there any package that can help with that, or do I have to write the Elisp with a parser myself?

I found https://alejandrogallo.github.io/listex/ which seems to be for writing LaTeX in Lisp. I do not want to write LaTeX in Lisp. I want to convert already written valid Lisp expressions to LaTeX math expressions.


EDIT: Based on the accepted answer I ended up making a whole minor mode centering around this functionality.

Here's the link: https://github.com/Atreyagaurav/litex-mode

4
  • emacs.stackexchange.com/tags/elisp/info
    – Drew
    Feb 2, 2022 at 19:55
  • Is your question about LaTeX expressions in general or just LaTeX math expressions. Please clarify the question for this.
    – Drew
    Feb 2, 2022 at 19:59
  • It's about latex math expressions. Also about the elisp tag info, the solution to this depends on parsing elisp expressions, so I considered it specific to elisp, I hope that tag is fine. Feb 2, 2022 at 20:16
  • No, tag elisp is not about using Elisp to do something. It's about Elisp as a particular Lisp dialect.
    – Drew
    Feb 2, 2022 at 21:34

1 Answer 1

4

Here is a toy function:

(defvar lisp2latex-need-parens nil)
(defun lisp2latex (form)
  (pcase form
    (`(+ . ,args)
     (let ((ret (let ((lisp2latex-need-parens nil))
                  (mapconcat #'lisp2latex args " + "))))
       (if lisp2latex-need-parens
           (concat "(" ret ")")
         ret)))
    (`(- ,a1 . ,args)
     (let ((ret
            (if args
                (format "%s - %s" (lisp2latex a1)
                        (let ((lisp2latex-need-parens t))
                          (mapconcat #'lisp2latex args " - ")))
              (format "- %s" (lisp2latex a1)))))
       (if lisp2latex-need-parens
           (concat "(" ret ")")
         ret)))
    (`(* . ,args)
     (let ((lisp2latex-need-parens t))
       (mapconcat #'lisp2latex args " \\times ")))
    (`(/ ,a1 . ,args)
     (if args
         (format "\\frac{%s}{%s}" (lisp2latex a1)
                 (lisp2latex (cons '* args)))
       (format "\\frac1{%s}" (lisp2latex a1))))
    (`(,func . ,args)
     (format "%s(%s)" func (mapconcat #'lisp2latex args ",")))
    (_ (prin1-to-string form))))

(lisp2latex '(* (/ (log 4 64)) (/ 3 (+ 4 6) 8)))
"\\frac1{log(4,64)} \\times \\frac{3}{(4 + 6) \\times 8}"

It probably adds too many parens...

7
  • That's like super fast, I can't believe how fast you did it, also it seems to work if I add other functions in the pcase, like (`(setq . ,args) (mapconcat #'lisp2latex args " = ")). Feb 2, 2022 at 20:14
  • I think your setq clause is wrong for more than 1 assignment.
    – sds
    Feb 2, 2022 at 20:16
  • I was also thinking that, but for now I just wanted to see if I could add any functions there. If it works then, can you modify the default expression to print function(arg1,arg2, ...) format instead of (function arg1 arg2 ...) format? Feb 2, 2022 at 20:18
  • I tried (_ (format "%s%s" (car form) (cdr form))) for the last one, and it does convert (sin 1) to sin(1) form, but again it doesn't work for multiple arguments. I tried (mapconcat #'lisp2latex (list (cdr form)) ", ") for second %s but it didn't work at all. Feb 3, 2022 at 2:48
  • what's wrong with my current version?
    – sds
    Feb 3, 2022 at 2:49

Your Answer

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

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