我需要使用 defmacro 来实现my_let *,它与let *类似,但是当let *扩展为一系列嵌套let调用(幕后)时,my_let *需要扩展进行单次调用调用,并使用 define 语句定义我得到的参数。
使用my_let *:
的示例 (my_let* ((a 2)
(b 3)
(c (+ a b)))
(+ a b c))
并且此代码的返回值应为10.就像使用let *一样。 上面的代码将在 my_let * 中扩展为以下代码:
(let ()
(define a 2)
(define b 3)
(define c (+ a b))
(+ a b c))
我是使用宏的新手,虽然我成功地写了一些宏,但这让我迷失了 提前谢谢。
答案 0 :(得分:3)
使用syntax-parse
。至少不要考虑在Racket中使用defmacro
。
#lang racket
(require (for-syntax syntax/parse))
(define-syntax (my-let* stx)
(syntax-parse stx
[(_my-let* ([name:id e:expr] ...) body ...)
#'(let ()
(define name e) ...
body ...)]))
name:id
表示name
必须是标识符,e:expr
表示
那个e
必须是一个表达式。这些简单的注释有助于语法分析
给你更好的错误信息。
示例:
(my-let* ((4 2)
(b 3)
(c (+ a b)))
(+ a b c))
DrRacket将为4读取颜色并给出消息:
my-let*: expected identifier in: 4
答案 1 :(得分:0)
Scheme方式正在使用syntax-rules
(define-syntax my-let*
(syntax-rules ()
((_ ((binding expression) ...) body ...)
(let ()
(define binding expression) ...
body ...))))
使用defmacro
更像是制作程序。
(define (my-let-fun* bindings . body)
...)
它应该如何工作是这样的:
(my-let-fun* '((a 1) (b 2) (c (+ a b))) "test" '(list a b c))
; ==> (let () (define a 1) (define b 2) (define c (+ a b)) "test" (list a b c))
如果您未在实施中调用my-let-fun*
,则只需将其更改为defmacro
即可。
(defmacro my-let* (bindings . body)
...)
使用帮助程序进行递归或foldr
进行绑定非常简单。祝你好运!
您的my-let*
仅适用于#lang racket
,也许#!r6rs
及更高版本。在R5RS中,在这种情况下您将收到错误:
(my-let* ((a 1) (b 2) (c (+ a b)))
(list a b c))
; signals an error that a is undefined.
原因是它扩展到这样的东西:
(let ((a 'undefined) (b 'undefined) (c 'undefined))
(let ((tmp1 1) (tmp2 2) (tmp3 (+ a b)))
(set! a tmp1)
(set! b tmp2)
(set! c tmp3))
(list a b c))
答案 2 :(得分:0)
在错误消息和宏步进器的一些明智使用之间,我认为这里很难出错。麻烦只是确保你使用conses或unquote-sclicing把事情放在一起。我相信这些宏的标准做法是大量使用quasiquote和unquote-splicing,以使输出尽可能与预期的语句紧密匹配,否则宏可能变得非常难以理解。但我不是defmacro
专家。
#lang racket/base
(require (for-syntax racket/base)
compatibility/defmacro)
(defmacro my-let* (binding-pairs . body)
(define defines (map (lambda (bp) (cons 'define bp)) binding-pairs))
`(let ()
,@defines
,@body))
(my-let* ((a 2)
(b (expt a 3)))
(printf "a:~a\nb:~a\n" a b)
(+ a b))