用 Scheme 作为 TEX的扩展语言

\eval 就可以在TEX文件里插入一段 Scheme. 当运行第二次tex2page 的时候,代码的运行结果就会被插入TEX文件。你可以用这些代码来改变 tex2page 的行为。

比如下面的代码将会打印 \sqrt2 的值:1.4142135623730951

\eval{ (display (sqrt 2)) }

你可以想象一下,你能用 Scheme 在TEX里做什么吗?你几乎无所 不能!

看看第 16 章,里面有一些我自己定义的函数,可以随 意操纵文档的排版方式。我看了一会儿 tex2page 的代码就想出了几 乎所有我用的着的中文解决方案。

现在我把一个 coroutine 的测试代码放在这里,看看是什么结 果:

(require (lib "defmacro.ss"))
(define-macro coroutine
  (lambda (x . body)
    `(letrec ((+local-control-state
               (lambda (,x) ,@body))
              (resume
               (lambda (c v)
                 (call/cc
                  (lambda (k)
                    (set! +local-control-state k)
                    (c v))))))
       (lambda (v)
         (+local-control-state v)))))

(define make-matcher-coroutine
  (lambda (tree-cor-1 tree-cor-2)
    (coroutine dont-need-an-init-arg
      (let loop ()
        (let ((leaf1 (resume tree-cor-1 'get-a-leaf))
              (leaf2 (resume tree-cor-2 'get-a-leaf)))
          (if (eqv? leaf1 leaf2)
              (if (null? leaf1) #t (loop))
              #f))))))

(define make-leaf-gen-coroutine
  (lambda (tree matcher-cor)
    (coroutine dont-need-an-init-arg
      (let loop ((tree tree))
        (cond ((null? tree) 'skip)
              ((pair? tree)
               (loop (car tree))
               (loop (cdr tree)))
              (else
               (resume matcher-cor tree))))
      (resume matcher-cor '()))))

(define tree-match?
  (lambda (tree1 tree2)
    (letrec ((tree-cor-1
              (make-leaf-gen-coroutine
               tree1
               (lambda (v) (matcher-cor v))))
             (tree-cor-2
              (make-leaf-gen-coroutine
               tree2
               (lambda (v) (matcher-cor v))))
             (matcher-cor
              (make-matcher-coroutine
               (lambda (v) (tree-cor-1 v))
               (lambda (v) (tree-cor-2 v)))))
      (matcher-cor 'start-ball-rolling))))

(define tree1 '(((a b) (y z)) (3 4)))
(define tree2 '(((a b) (t z)) (3 4)))
(define tree3 '(((a (b y) z)) (3 4)))

(define (display-line str . rest)
  (for-each display
            (cons str rest))
  (newline))

(if (tree-match? tree1 tree2)
    (display-line "tree1 and tree2 match. ")
    (display-line "tree1 and tree2 don't match. "))

(if (tree-match? tree1 tree3)
    (display-line "tree1 and tree3 match. ")
    (display-line "tree1 and tree3 don't match. "))

结果是:tree1 and tree2 dont match. tree1 and tree3 match.

最后的结果就是 tex2page 交给 Scheme 解释器处理以后送回的结果。 这对与撰写 Scheme 文献非常有好处。