../
邪道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