How to create Alist from List using syntax-rules in Scheme?

87 Views Asked by At

Just as exercise I want to transform:

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

into

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

is this possible with syntax-rules?

My attempt:

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

the problem that it expand into:

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

is macro alist possible with syntax-rules? How it should look like?

EDIT:

Another attempt

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

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

2

There are 2 best solutions below

3
On BEST ANSWER

If it's literals only (like "foo" and 2) you can just do this:

#!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

Of course you are not allowed to mutate this because (alist a b c d) is the same as literally writing '((a . b) (c . d)) which you are not allowed to mutate.

Also if you ever make an alist with alist-builder as the first key the internals will leak. You can fix this by splitting up the internal definition and you can hide it from exposure by having both in a library and only export alist

1
On

I've figure that out:

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

and simplified version:

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