../
邪道Scheme
==========

2022-12-13

因为Scheme和Lisp系的其他语言一样,过于灵活,因此可以往语言里面加入很多奇怪的东
西。甚至,如果想用命令式的方式,像Python一样编写Scheme代码,也是可以的。

这篇文章中的代码都是为GNU Guile和TinyScheme而写的,这两个解释器都支持老式的Lisp
宏。这种宏在Common Lisp当中更多见,并不卫生,也不属于任何Scheme标准。但是大多数
解释器和编译器都支持。

例如,假如想在Racket中运行,只需要在代码前面加入下面这段语法就可以了:

    #lang racket
    
    (define-syntax define-macro
      (lambda (x)
        (syntax-case x ()
          ((_ (macro . args) body ...)
           #'(define-macro macro (lambda args body ...)))
          ((_ macro transformer)
           #'(define-syntax macro
               (lambda (y)
                 (syntax-case y ()
                   ((_ . args)
                    (let ((v (syntax->datum #'args)))
                      (datum->syntax y (apply transformer v)))))))))))

## hello, world

Python代码:

    print("hello, world")

函数定义:

    (define println
        (lambda x
          (apply display x)
          (newline)))

最终效果:

    (println "hello world")

## Def

Python代码:

    def is_even(x):
        if x % 2 == 0:
            return True
        return False

宏定义:

    (define-macro (def form . body)
        `(define ,form
             (call/cc (lambda (return)
                ,@body))))

最终效果:

    (def (is-even x)
        (cond ((= 0 (modulo x 2))
            (return #t)))
        (return #f))


## While

Python代码:

    i = 0
    while True:
        i = i + 1
        if x % 2 == 0:
            continue
        print(i)
        if i > 10:
            break


宏定义:

    (define-macro (while condition . body)
        (let ((loop (gensym)))
            `(call/cc (lambda (break)
                (letrec ((,loop (lambda ()
                    (cond (,condition
                        (call/cc (lambda (continue)
                                ,@body))
                        (,loop))))))
                    (,loop))))))


最终效果:

    (let ((i 0))
    (while #t
        (set! i (+ i 1))
        (cond ((= (modulo i 2) 0)
             (continue)))
        (cond ((> i 10)
            (break)))
        (println i)))


# For

Python代码:

    for i in range(0, 10):
        print(i)


宏和工具函数定义:

    (define (iter-get iter)
        (cond ((list? iter)
            (car iter))
        (else
            (iter 'get))))
    
    (define (iter-next iter)
        (cond ((list? iter)
            (cdr iter))
        (else
            (iter 'next))))
    
    (define (range start end)
        (lambda (method)
            (cond ((eq? 'get method)
                (if (>= start end)
                    '()
                    start))
            ((eq? 'next method)
                (range (+ 1 start) end)))))
    
    (define-macro (for i range . body)
        (let ((loop (gensym))
              (iter (gensym)))
        `(call/cc (lambda (break)
            (letrec
                ((,loop (lambda (,iter)
                    (if (eq? (iter-get ,iter) '())
                        '()
                        (let ((,i (iter-get ,iter)))
                              (call/cc (lambda (continue)
                                 ,@body))
                              (,loop (iter-next ,iter)))))))
                (,loop ,range))))))


最终效果:

    (for i (range 0 10)
        (println i))


## Goto

这个还是算了吧!

## Fizz Buzz!

Python写出来是这样:

    for i in range(35):
        if i % 15 == 0:
            print("FizzBuzz")
            continue
        if i % 3 == 0:
            print("Fizz")
            continue
        if i % 5 == 0:
            print("Buzz")
            continue
        print(i)

用Scheme的话,加上上面的宏,几乎可以一一对应:

    (for i (range 1 35)
        (cond ((= 0 (modulo i 15))
            (println "FizzBuzz")
            (continue)))
        (cond ((= 0 (modulo i 3))
            (println "Fizz")
            (continue)))
        (cond ((= 0 (modulo i 5))
            (println "Buzz")
            (continue)))
        (println i))




--------------------------------------------------------------------
Email: i (at) mistivia (dot) com