如何使用Scheme中的语法规则从List创建Alist?

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

就像运动一样我想改造:

(alist "foo" 1 "bar" 2 "baz" 3)

进入

(("foo" . 1) ("bar" . 2) ("baz" . 3))

这可以通过语法规则实现吗?

我的尝试:

(define-syntax alist
  (syntax-rules ()
     ((_ a b) (cons a b))
     ((_ x y ...)
      (list (alist x y) ...))))

它扩展成的问题:

(("foo" . 2) ("foo" . "bar") ("foo" . 4) ("foo" . "baz") ("foo" . 6))

宏列表可以通过语法规则实现吗?它应该是什么样子?

编辑:

又一次尝试

(define-syntax alist
  (syntax-rules ()
     ((_ a b) (cons a b))
     ((_ x y z ...)
      (list (alist x y) (alist z ...)))))

它返回

(("foo" . 2) (("bar" . 4) ("baz" . 6)))

macros scheme hygiene syntax-rules
2个回答
2
投票

我已经弄清楚了:

(define-syntax alist
  (syntax-rules ()
     ((_) ())
     ((_ a b) (list (cons a b)))
     ((_ x y z ...)
      (apply list (cons x y) (alist z ...)))))

和简化版本:

(define-syntax alist
  (syntax-rules ()
     ((_) ())
     ((_ a b) (list (cons a b)))
     ((_ x y z ...)
      (cons (cons x y) (alist z ...)))))

1
投票

如果它只是文字(如

"foo"
2
),你可以这样做:

#!r6rs
(import (rnrs))

(define-syntax alist
  (syntax-rules (alist-builder)
    ((_ alist-builder () (results ...)) 
     '(results ...))
    ((_ alist-builder (a) . rest) 
     (raise 'bad-alist))
    ((_ alist-builder (a b rest ...) (results ...))
     (alist alist-builder (rest ...) (results ... (a . b))))
    ((_ a ...) (alist alist-builder (a ...) ()))))

(alist)         ; ==> ()
(alist "a" 2)   ; ==> (("a" . 2))
(alist a 3 b 4) ; ==> ((a . 3) (b . 4))
(alist a)       ; ==> uncaught exception: bad-alist

当然你不可以改变它,因为

(alist a b c d)
与字面上写的
'((a . b) (c . d))
是一样的,你不可以改变它。

此外,如果您使用

alist-builder
作为第一个键创建 alist,内部结构将会泄漏。您可以通过拆分内部定义来解决此问题,并且可以通过将两者都放在库中并仅导出来隐藏它以防止暴露
alist

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