lovingxiaobing 发表于 2019-12-5 01:58

LISP(SCHEME) 捏一个for和while循环

总所周知,LISP中没有循环,想要循环就得递归。
我们可以用 call/cc 来捏一个循环,call/cc会跳回原来的点往下执行,关于 延续(continuation)相关的其他更深入的东西这里不赘述。

创建一个call/cc为A
在这个A中再创建一个call/cc为B
在B的位置下面就是循环体过程
此时A为break,B就为continue(默认调用继续循环)
循环的次数由循环的条件决定要不要continue。

下面就上全部代码(用lisp的scheme方言实现)

; author: 小冰哟
; email: 865741184@qq.com
;      lovingxiaobing@qq.com

; (while! (conditional) (lambda (continue break) ...))
(define-syntax while!
(syntax-rules ()
    ((while! (conditional) body)
      (call/cc (lambda (_break)
               (let ((_continue 0))
                   (call/cc (lambda (__continue)
                              (set! _continue __continue)))
                              (if conditional
                              (begin (body _continue _break)
                                       (_continue))
                              (_break))))))))


(define-syntax for!
(syntax-rules ()
    ((for! () body)
      (while (#t) body))
    ((for! (() () ()) body)
      (for! ()))
    ((for! ((binds ...)) body)
      (for! ((binds ...) #t) body))
    ((for! ((binds ...) conditional))
      (let* (binds ...)
      (while! (conditional) body)))
    ((for! ((binds ...) conditional (validates ...)) body)
      (let* (binds ...)
      (letrec ((_validates (lambda () validates ...)))
          (while! (conditional)
            (lambda (continue break)
            (body (lambda () (_validates) (continue))
                  break)
            (_validates))))))))


; 测试 for! : 输出0~20内10以内的奇数
(for! (((m 0)) (< m 20) ((set! m (+ m 1))))
(lambda (continue break)
    (if (zero? (modulo m 2))
      (continue))
    (if (>= m 10)
      (break))
    (display m)
    (newline)))


在贴这段代码时,竟然没有scheme格式的。
为了方便,就做成宏。上面的代码可直接使用,没有任何递归带来的开销。for其实完全是在while的基础上模拟的,欢迎大家来找茬!!

贴运行结果:



页: [1]
查看完整版本: LISP(SCHEME) 捏一个for和while循环