SMathML: A Set of Programs to Write Math on the Web

SMathML
Recently I decide to translate Hoffman & Kunze into Chinese. And I also want to put it on my homepage. Then I write down these programs to generate html, mathml, svg, and so on. Here is an example I pick up from the source code of the translation.


3 Likes

These look useful.
Are these to turn mathematical expressions into stand-lone images that
are patched into a document by other means,
or are they part of a larger document compiler?

-- hendrik

1 Like

I think I have to explain my ideas in detail. There is no magic.
In fact, mathematical expressions are rendered by the browser (Firefox) through MathML. MathML is a markup language based on XML.
There is a hierarchical structure in my mind. First, I define a represention for XML, which is just kind of XML in S-exp (SXML).

<xml> ::= <string>
       |  (<symbol> (<attr>*) <xml>*)
<attr> ::= (<symbol> <string>)

In xml.rkt, I provide a procedure Xml for transformation. For example,

> (Xml '(foo ((bar "baz")) "qux"))
<foo bar="baz">qux</foo>

In html.rkt, I provide lots of procedures to create HTML (in SXML). For instance,

> (Xml (Prelude (H1 "foo") (P "foo " (B "bar") " baz")))
<html><head><meta charset="utf-8"/><title>index</title></head><body><h1>foo</h1><p>foo <b>bar</b> baz</p></body></html>

As you may expect, mathml.rkt provide tons of procedures to create MathML (in SXML) and to build abstractions for creating MathML. For example, we have procedure make-op which transforms an infix operator into a procedure by which you may write MathML in the style of Scheme.

(define ((make-op op n u) . x*)
  (cond
    ((null? x*) (n))
    ((null? (cdr x*)) (u (car x*)))
    (else
     (let iter ((x (car x*)) (x* (cdr x*)) (r '()))
       (if (null? x*)
           (apply Mrow (reverse (cons x r)))
           (iter (car x*)
                 (cdr x*)
                 (cons op (cons x r))))))))

For example,

(define &cm
  (make-op $cm
    (lambda () $)
    (lambda (x) x)))
> (Xml (&cm))
<mrow/>
> (Xml (&cm $1))
<mn>1</mn>
> (Xml (&cm $1 $2))
<mrow><mn>1</mn><mo>,</mo><mn>2</mn></mrow>
> (Xml (&cm $1 $2 $3))
<mrow><mn>1</mn><mo>,</mo><mn>2</mn><mo>,</mo><mn>3</mn></mrow>

In slt.rkt, I provide some abstractions to build tree transformations. (These are inspired by Oleg Kiselyov's SXSLT.) For now they haven't been efficiently implemented and I'd like to modify them in the future. As an illustration of the usage, I provide a procdure Tm in math-styles.rkt.

(define math-style*
  `(((default)
     *preorder*
     ,(lambda (tag attr* . xml*)
        (cond ((eq? tag 'math) `(,tag ,attr* . ,xml*))
              ((memq tag '(merror mfrac mi mmultiscripts mn mo mover
                                  mpadded mphantom mroot mrow
                                  ms mspace msqrt mstyle msub msubsup
                                  msup mtable mtd mtext mtr munder
                                  munderover))
               (Math `(,tag ,attr* . ,xml*)))
              (else `(,tag ,attr* . ,(map Tm xml*))))))
    ((text) ,(lambda (str) str))))
(define Tm (T math-style*))
1 Like