Skip to content

Instantly share code, notes, and snippets.

@bpanthi977
Last active February 6, 2022 03:24
Show Gist options
  • Save bpanthi977/4b8ece0eeff3bc05bb82275a23cbb56d to your computer and use it in GitHub Desktop.
Save bpanthi977/4b8ece0eeff3bc05bb82275a23cbb56d to your computer and use it in GitHub Desktop.
Convert mathematical lisp expression to LaTeX
;; improved from https://emacs.stackexchange.com/a/70360
(defvar lisp2latex-functions '(sin cos tan))
(defvar lisp2latex-maybe-enclose? nil)
(defun lisp2latex-maybe-enclose (form)
(let* ((lisp2latex-maybe-enclose? nil)
(latex (lisp2latex form)))
(if lisp2latex-maybe-enclose?
(format "(%s)" latex)
latex)))
(defun lisp2latex (form)
"Converts given lisp expression to latex equivalent"
(pcase form
;; basic operators
(`(+ . ,args)
(setf latex-maybe-enclose t)
(mapconcat #'lisp2latex args " + "))
(`(* . ,args)
(setf latex-maybe-enclose t)
(with-output-to-string
(loop for (me next . rest) on args do
(if (numberp next)
(princ (format "%s \\times " (lisp2latex-maybe-enclose me)))
(princ (format "%s " (lisp2latex-maybe-enclose me)))))))
(`(/ ,a1 . ,args)
(if args
(format "\\frac{%s}{%s}" (lisp2latex a1)
(lisp2latex (cons '* args)))
(format "\\frac1{%s}" (lisp2latex a1))))
(`(- ,a1 . ,args)
(if args
(format "%s - %s" (lisp2latex a1)
(mapconcat #'lisp2latex args " - "))
(format "- %s" (lisp2latex a1))))
(`(expt ,base ,power)
(if (listp base)
(format "(%s)^{%s}" (lisp2latex base) (lisp2latex power))
(format "%s^{%s}" (lisp2latex base) (lisp2latex power))))
;; assignment operator
(`(setq . ,args)
(with-output-to-string
(loop for (a b . rest) on args by #'cddr do
(princ (format "%s = %s" (lisp2latex a) (lisp2latex b)))
(when rest (princ "; ")))))
;; other operators
(`(1+ ,arg) (concat "1 + " (lisp2latex arg) ))
(`(,func . ,args)
(let* ((known? (find func lisp2latex-functions))
(enclose? (or (not known?)
(> (length args) 1)
(listp (first args))))
(format-string (concat (if known? "\\%s" "\\mathrm{%s}")
(if enclose? "(%s)" " %s"))))
(format format-string func (mapconcat #'lisp2latex args ","))))
(_
(cond ((floatp form)
(if (or (< form 1e-2) (> form 1e4))
(let* ((exponent (floor (log form 10)))
(front (/ form (expt 10 exponent))))
(format "%.2f \\times 10^{%d}" front exponent))
(format "%.3f" form)))
(t (prin1-to-string form))))))
(defun lisp2latex3 (form)
(pcase form
(`(setq ,var ,expression)
(with-output-to-string
;; expression
(princ (lisp2latex form))
(princ " \\\\\n")
(flet ((subst-vars (e)
(cond ((listp e)
(cons (first e) (mapcar #'subst-vars (rest e))))
((symbolp e)
(symbol-value e))
(t e))))
(let ((substituted-expression (subst-vars expression))
(varLatex (lisp2latex var)))
(princ (format "%s = %s \\\\ \n" varLatex (lisp2latex substituted-expression)))
(princ (format "%s = %s" varLatex (eval substituted-expression)))))))
(_ (lisp2latex form))))
(defun lisp2latexn% (form)
(cond ((listp form)
(if (every #'numberp (rest form))
(eval form)
(cons (first form) (mapcar #'lisp2latexn% (rest form)))))
((symbolp form)
(symbol-value form))
(t form)))
(defun lisp2latexn (form)
(pcase form
(`(setq ,var ,exp)
(with-output-to-string
;; expression
(princ (lisp2latex form))
(princ " \\\\\n")
(loop for new-exp = (lisp2latexn% exp)
with varLatex = (lisp2latex var)
do
(if (eql exp new-exp)
(return))
(princ (format "%s = %s\\\\\n" varLatex (lisp2latex new-exp)))
(setf exp new-exp))))
(_ (lisp2latex form))))
(defun lisp-to-latex ()
(interactive)
(backward-kill-sexp)
(insert (lisp2latex (read (current-kill 0)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment