Macros DrRacket中的While循环宏
我正在尝试为DrRacket中的while循环创建宏。以下是我写的:Macros DrRacket中的While循环宏,macros,scheme,racket,Macros,Scheme,Racket,我正在尝试为DrRacket中的while循环创建宏。以下是我写的: (require mzlib/defmacro) (define-macro my-while (lambda (condition body) (list 'local (list (list 'define (list 'while-loop) (list 'if condition
(require mzlib/defmacro)
(define-macro my-while
(lambda (condition body)
(list 'local (list (list 'define (list 'while-loop)
(list 'if condition
(list body (list 'while-loop))
'(void))))
'(while-loop))))
(define x 0)
(my-while (< x 10)
(begin
(display x)
(newline)
(set! x (+ x 1))))
(需要mzlib/defmacro)
(定义我的宏)
(lambda(状态体)
(列表“本地”(列表“定义(列表)”while循环)
(列出“如果条件”
(列表主体(列表的while循环))
"(无效))
“(while循环)))
(定义x 0)
(我的时间(
该程序的输出为:
0
1
2
3
4
5
6
7
8
9
error: procedure application: expected procedure, given: #<void>; arguments were: #<void>
0
1.
2.
3.
4.
5.
6.
7.
8.
9
错误:过程应用程序:预期过程,给定:#;论点如下:#
有人能帮我吗?为什么这个宏不能终止并返回void呢。似乎当条件为非真时,系统会尝试将void作为参数应用于某些过程 哎哟
while
循环会鼓励过度使用命令式编程define macro
创建不卫生的宏,这在Scheme中是一场噩梦define宏版本供您参考:
(define-syntax-rule (my-while condition body ...)
(let loop ()
(when condition
body ...
(loop))))
它使用语法规则
,可以创建卫生的宏,并且比现有的要容易得多
现在,对于您问题的实际答案,首先,让我们以更可读的方式写出原始宏:
(define-macro my-while
(lambda (condition body)
`(local ((define (while-loop)
(if ,condition
(,body (while-loop))
(void))))
(while-loop))))
以这种方式写出来后,您可以看到真正的问题在哪里:在(,body(while loop))
行中,应该是(begin,body(while loop))
,另一个版本的while使用do循环:
(define-syntax while
(syntax-rules ()
((while pred? stmt ...)
(do () ((not pred?))
stmt ...))))
当普通的旧函数可以使用时,为什么要使用宏
;; fun-while : (-> Boolean) (-> Any) -> Void
(define (fun-while condition body)
(when (condition)
(body)
(fun-while condition body))
当然,这需要您传入可调用的可重复操作(这就是为什么条件
和主体
在乐趣的主体中被paren包围的原因,而乐趣的主体
),因此如果您想要更漂亮的语法,确实需要一个宏。但是,一旦你有了一个具有所需行为的函数,在上面放一些糖对于这种情况来说是微不足道的:
(define-syntax-rule (my-while condition body ...)
(fun-while (lambda () condition)
(lambda () body ...)))
现在,正如已经说过的,这鼓励了命令式风格,这是不受欢迎的。请尝试将状态显式化,而不是突变:
;; pure-while : forall State.
;; (State -> Boolean) ; the "condition" that inspects the state
;; (State -> State) ; the "body" that moves from one state to the next
;; -> ; curried
;; State ; the current state
;; -> State ; produces the ending state
(define ((pure-while condition make-next) current-state)
(if (condition current-state)
(pure-while condition make-next (make-next current-state))
current-state))
您会注意到,前两个参数现在是从State
到某物的函数,应用于两个参数的结果也是从State->State
到某物的函数。这是一个反复出现的模式,作为Haskell,我将其称为“状态蒙纳德”。关于将糖放在这个概念之上的讨论超出了本次对话的范围,所以我就到此为止。因为已经有一段时间了:
球拍6.0的while
宏
#lang racket
(define-syntax while
(syntax-rules ()
((_ pred? stmt ...)
(do () ((not pred?))
stmt ...))))
真的,真的。但我今天才第一次看到一个宏(在Fixnum天的自学计划中)。还在学习。我还没有读过关于卫生宏的书。@RajeshBhat:另外,我刚刚更新了我的答案,解释了为什么你的不卫生宏不起作用。:-)当然,我仍然鼓励你使用卫生版@RajeshBhat宏是一项世界性的研究。Fixnum天中的方案很好,但有关宏的部分已经过时。如果我是你,我会找到一个介绍宏使用语法规则或语法大小写。我可以推荐《球拍指南》中的介绍:这确实有效,尽管do
循环通常会宏扩展为基于命名的let
循环,而且许多策划人告诉我,命名的let
循环比do
循环更惯用,后者更……CL风格