【问题标题】:Nested macros in RacketRacket 中的嵌套宏
【发布时间】:2014-01-12 21:51:05
【问题描述】:

我希望能够编写这样的嵌套表达式:

(AND/OR expr1 op1 expr2 AND/OR expr3 op2 expr4 and so on)

AND/OR 本质上是 AND 或 OR。但我希望能够写出无限数量的它们。我正在使用define-syntax 来尝试实现这一点,但我不确定如何接受无限数量的嵌套表达式。

不要介意我的例子中的 expr 和 op,这部分我可以自己处理。我只想知道如何接受无限嵌套。

例子:

(SELECT somecolumns
FROM sometable
WHERE something
AND/OR something
AND/OR (something AND/OR something)
AND/OR ...)

【问题讨论】:

  • 你有一些样本输入和样本预期输出吗?
  • 我用一个例子编辑了帖子,这可能会让事情更清楚。
  • 看起来你会从写像(AND/OR expr1 op1 expr2 (AND/OR expr3 op2 ...))这样的表达式中受益。然后你的宏自然会组成。否则,您将使用 s-expression 语法,这会使事情变得困难。

标签: macros nested scheme lisp racket


【解决方案1】:

正如 Asumu 所说,通常处理 s 表达式更简单,至少为了确保正确的运算符优先级,但对于一些简单的情况,syntax-rules(和syntax-parse 和 co)的模式匹配使这很容易,使用剩余参数和递归匹配:

#lang racket
(define-syntax parse-args
  (syntax-rules (AND) ; treat AND as a literal
    [(_)
     ; no more argument, return value:
     '()]

    [(_ (arg1 AND in-rst ...))
     ; Composed argument found, call parse-args recursively:
     (parse-args arg1 AND in-rst ...)]

    [(_ arg1 AND rst ...)
     ; AND operator found, parse left side and rest
     (list 'and
           ; parse the argument (may be composed or not):
           (parse-args arg1)
           ; then parse the rest of the arguments:
           (parse-args rst ...))]

    [(_ arg)
     ; in case the argument is not composed or does not contain AND, don't parse it
     arg]))

;; TESTS:
(parse-args 'a AND ('b AND 'bb) AND 'c AND 'f)
; -> '(and a (and (and b bb) (and c f)))

(parse-args 'a AND ('b AND 'bb))
; -> '(and a (and b bb))

但是,请注意,上面的代码在添加其他运算符时可能变得不切实际。

编辑: 与 select 宏一起使用:

(define-syntax SELECT
  (syntax-rules (FROM WHERE)
    [(_ select FROM from WHERE where ...)
     (list 'Select select 'From from 'Where (parse-args where ...))]))

; TEST:
(SELECT 'somecolumns
FROM 'sometable
WHERE 'something1
AND 'something2
AND ('something3 AND 'something4)
AND 'blop)
; -> 
#;'(Select
    somecolumns
    From
    sometable
    Where
    (and something1
         (and something2
              (and (and something3 something4) blop))))

同样,模式匹配允许在正确的点切割列表以获得其余参数

【讨论】:

  • 我绝对明白为什么这是一个合理的方法,但是否可以将它与上述语句语法(SELECT FROM WHERE)结合起来?对不起,如果我在这里有点迟钝,但球拍仍然让我感到困惑,因为我是新手。
  • 我已经编辑了我的答案以添加 SELECT 宏,但如果您不清楚,那么这可能不是最好的练习。我怀疑你对递归还不满意。如果是这种情况,您现在可能应该避免使用宏,并继续学习递归函数和其余参数。
  • 非常感谢。只是我对 Rackets 中的宏还不满意,我对其他函数式语言的递归非常熟悉。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-24
  • 1970-01-01
  • 2014-12-23
  • 2011-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多