⬑
邪道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