(Chez) 用于隐藏 lambda 的方案宏
(Chez) Scheme macro for hiding lambdas
我想编写一个宏来创建 shorthand 语法来隐藏更冗长的 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)))
有什么意见或建议吗?
我看到的直接问题是无法判断要选择哪个绑定。例如。 apply
是列表中的元素之一还是全局变量?那要看。我建议你这样做:
(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
做。例如。制作一个图案并写下替换物。祝你好运。
这是一个 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
将 shorthand 表达式扩展为名称和过程列表。
(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)))
上面 with-alist
用法的 3 个示例可以在对 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))
我想编写一个宏来创建 shorthand 语法来隐藏更冗长的 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)))
有什么意见或建议吗?
我看到的直接问题是无法判断要选择哪个绑定。例如。 apply
是列表中的元素之一还是全局变量?那要看。我建议你这样做:
(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
做。例如。制作一个图案并写下替换物。祝你好运。
这是一个 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
将 shorthand 表达式扩展为名称和过程列表。
(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)))
上面 with-alist
用法的 3 个示例可以在对 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))