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
  • Is your question about LaTeX expressions in general or just LaTeX math expressions. Please clarify the question for this.
    – Drew
    Feb 2 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 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 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 at 20:14
  • I think your setq clause is wrong for more than 1 assignment.
    – sds
    Feb 2 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 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 at 2:48
  • what's wrong with my current version?
    – sds
    Feb 3 at 2:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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