2

我想编写一个宏来创建用于隐藏更冗长的 lambda 表达式的速记语法,但我很难理解如何编写宏(我意识到这是反对使用它们的论据)。

给定这个例子:

(define alist-example
  '((x 1 2 3) (y 4 5 6) (z 7 8 9)))

(define ($ alist name)
  (cdr (assoc name alist)))

((lambda (a) (map (lambda (x y z) (+ x y z)) ($ a 'x) ($ a 'y) ($ a 'z))) alist-example)
((lambda (a) (map (lambda (y) (/ y (apply max ($ a 'y)))) ($ a 'y))) alist-example)

我想写一个宏,with-alist,它可以让我写出最后两个类似的表达式:

(with-alist alist-example (+ x y z))
(with-alist alist-example (/ y (apply max y)))

有什么意见或建议吗?

4

2 回答 2

1

我看到的直接问题是没有办法知道选择哪些绑定。例如。是applyalist 中的元素之一还是全局变量?那要看。我建议你这样做:

(with-alist ((x y z) '((x 1 2 3) (y 4 5 6) (z 7 8 9)))
  (+ x y z))

(let ((z 10))
  (with-alist ((x y) alist-example)
    (+ x y z)))

它应该转化为:

(let ((tmp '((x 1 2 3) (y 4 5 6) (z 7 8 9))))
  (apply map (lambda (x y z) (+ x y z))
         (map (lambda (name) ($ tmp name)) '(x y z))))

(let ((z 10))
  (let ((tmp alist-example))
    (apply map (lambda (x y) (+ x y z))
           (map (lambda (name) ($ tmp name)) '(x y)))))

这就是直截了当的处理syntax-rules。例如。制作一个图案并写下替换。祝你好运。

于 2020-03-11T00:21:50.110 回答
1

这是syntax-rules基于我在其他答案和评论中收到的反馈的解决方案:

(define ($ alist name)
  (cdr (assoc name alist)))

(define-syntax with-alist
  (syntax-rules ()
    [(_ alist names expr)
     (let ([alist-local alist])
       (apply map (lambda names expr)
              (map (lambda (name) ($ alist-local name)) (quote names))))]))

这是一些示例用法:

> (define alist-example
  '((x 1 2 3) (y 4 5 6) (z 7 8 9)))
> (with-alist alist-example (x) (+ x 2))
(3 4 5)
> (with-alist alist-example (x y) (+ x y))
(5 7 9)
> (with-alist alist-example (x y z) (+ x y z))          
(12 15 18)

在我的问题中,这个答案没有解决更复杂的例子,(with-alist alist-example (/ y (apply max y)))但我认为这对于我的目的来说是一种合理的方法:

> (with-alist alist-example (y) (/ y (apply max ($ alist-example 'y))))
(2/3 5/6 1)

编辑:经过一些额外的修改,我得出了一个稍微不同的解决方案,我认为它会提供更大的灵活性。

我的新宏npl将速记表达式扩展为名称和过程列表。

(define-syntax npl
  (syntax-rules ()
    [(_ (names expr) ...)
     (list 
      (list (quote names) ...)
      (list (lambda names expr) ...))]))

这个宏的输出被传递给一个常规过程,with-list-map它包含上述with-alist宏中的大部分核心功能。

(define (with-alist-map alist names-proc-list)
  (let ([names-list (car names-proc-list)]
        [proc-list (cadr names-proc-list)])
    (map (lambda (names proc)
           (apply map proc
                  (map (lambda (name) ($ alist name)) names)))
         names-list proc-list)))

上面的 3 个使用示例with-alist可以在一次调用中捕获with-alist-map

> (with-alist-map alist-example
                (npl ((x) (+ x 2))
                     ((x y) (+ x y))
                     ((x y z) (+ x y z))))
((3 4 5) (5 7 9) (12 15 18))
于 2020-03-18T00:20:29.567 回答