Last active
February 6, 2022 03:24
-
-
Save bpanthi977/4b8ece0eeff3bc05bb82275a23cbb56d to your computer and use it in GitHub Desktop.
Convert mathematical lisp expression to LaTeX
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 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