Macros Racket-使用宏实现let*函数

Macros Racket-使用宏实现let*函数,macros,scheme,lisp,racket,let,Macros,Scheme,Lisp,Racket,Let,我需要使用与let*类似的defmacro来实现我的_let*,但是当let*扩展为一系列嵌套的let调用(幕后)时,我的_let*需要扩展为一个单个let调用,并使用define语句来定义我得到的参数 使用my_let*的示例如下: (my_let* ((a 2) (b 3) (c (+ a b))) (+ a b c)) 这个代码的返回值应该是10。就好像它是use let*。 上述代码将在my_let*中展开为以下内容: (let () (define a 2) (defin

我需要使用与let*类似的defmacro来实现我的_let*,但是当let*扩展为一系列嵌套的let调用(幕后)时,我的_let*需要扩展为一个单个let调用,并使用define语句来定义我得到的参数

使用my_let*的示例如下:

 (my_let* ((a 2)
 (b 3)
 (c (+ a b)))
 (+ a b c))
这个代码的返回值应该是10。就好像它是use let*。 上述代码将在my_let*中展开为以下内容:

(let ()
 (define a 2)
 (define b 3)
 (define c (+ a b))
 (+ a b c))
我不熟悉使用宏,虽然我成功地编写了一些宏,但这一个让我迷路了。

提前谢谢。

方案方式是使用
语法规则

(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))
(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))
如果在实现中没有调用
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.
原因是它扩展到如下内容:

(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))
(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))

在错误信息和明智地使用宏步进器之间,我认为这里很难出错。问题是要确保使用conses或unquote拼接来正确地组合事物。我相信在这种宏中的标准实践是大量使用准引号和非引号拼接,以便输出尽可能接近预期语句,否则宏可能变得相当难以理解。但我不是
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))

使用
语法分析
。至少在球拍上不要考虑使用<代码> Debug宏>代码> 

#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

两个问题:您真的想使用
defmacro
,而不是(更简单的)
define syntax
syntax rules
,以及类似的工具,因为兼容的原因,哪种Racket有?另外,您建议的扩展实际上与
let*
不同,因为
let*
允许您隐藏以前的绑定,而
define
不允许。你同意吗?@BrendanCannell在本例中是的,因为它是赋值的一部分(其中一部分是宏)。我仍然想了解define语法的使用。(也许这是未来将要学习的课程的一部分。)好的。也许你可以告诉我们你做了什么,你在想什么,这样我们就可以为你指明正确的方向。@BrendanCannell,正如我前面提到的。这个让我迷路了。我确实成功地编写了其他宏,但即使使用(define x y)来定义变量对我来说也是新的,因为我们总是使用(let x y)来定义变量。此外,我无法判断内部助手函数在这里应该做什么。我无法合理地猜测您的定义中出现了什么错误,因为您没有将其提供给我们。那么唯一的答案就是简单地为您编写代码。甚至没有什么可以解释的。这真的是你想要的吗?