如何在循环中定义多个变量,其名称由模板指定?

问题描述 投票:0回答:1

我想重构这种模式,其中许多顶级变量都使用给定的命名方案分配。

#lang racket

(define ((f-x/y x y) z)
  ;; nominal example
  (list x y z))

(match-define (list f-a/a f-a/b f-a/c
                    f-b/a f-b/b f-b/c
                    f-c/a f-c/b f-c/c)
  (for*/list ([x '(a b c)]
              [y '(a b c)])
    (f-x/y x y)))

(f-b/a 'd) ;; => '(b a d)

问题似乎有两个方面:在循环内定义任何内容,以便可以在外部看到它(违反词法范围?),并定义一个名称由模板创建的变量。

理想情况下,这样的事情是可能的;

format-id
至少看起来是正确的方向。

(require racket/syntax)

;; notional
(for*/defs ([x '(a b c)]
            [y '(a b c)])
  (define (format-id #'x "f-~a/~a" x y)
    (f-x/y x y)))

就其价值而言,所有

'(a b c)
元素都是固定的并且在编译时是已知的。上面的第一个代码块可以工作并且在实践中很好,但我真的很想学习可能存在的解决此类问题的宏观技术。

macros scheme lisp racket
1个回答
0
投票

我以前做过类似的事情,是的,

format-id
是正确的方法。词法上下文可以只是传递给使用该函数的宏的顶级语法对象。

一个例子:

#lang racket/base

(require (for-syntax racket/base racket/list racket/syntax syntax/parse))

(define ((f-x/y x y) z) (list x y z))

(define-syntax (define-all-options stx)
  (syntax-parse stx ; Use syntax-parse instead of syntax-case to get type checks in the macro pattern
    [(_ f:id (sym:id ...))
     (let* ([symbols (syntax->list #'(sym ...))] ; list of syntax objects for the given symbol
            [pairs (cartesian-product symbols symbols)] ; every combination of 2 ids
            [identifiers ; build the names of the functions to define
             (for/list ([combo (in-list pairs)])
               (format-id stx "f-~a/~a" (first combo) (second combo)))]
            [constructors ; build the function calls whose return values are bound to the above names
             (for/list ([combo (in-list pairs)])
               #`(f #,@combo))])
       ;; and put all the parts together
       #`(define-values #,identifiers (values #,@constructors)))]))

(define a 'a)
(define b 'b)
(define c 'c)
(define-all-options f-x/y (a b c))
(println (f-a/b 'd))

我发现最好只采用文字标识符而不是引用列表,以保持宏中的简单。这确实意味着需要在调用宏之前定义这些标识符。

© www.soinside.com 2019 - 2024. All rights reserved.