(Chez) Схема макроса для сокрытия лямбд - PullRequest
2 голосов
/ 11 марта 2020

Я хотел бы написать макрос для создания сокращенного синтаксиса для сокрытия более многословных лямбда-выражений, но я пытаюсь понять, как писать макросы (что, как я понимаю, является аргументом против их использования).

Учитывая этот пример:

(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)))

Любой совет или предложения?

Ответы [ 2 ]

1 голос
/ 18 марта 2020

Вот решение 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))
1 голос
/ 11 марта 2020

Непосредственная проблема, которую я вижу, заключается в том, что невозможно определить, какие привязки выбрать. Например. apply является одним из элементов в alist или это глобальная переменная? Это зависит от. Я предлагаю вам сделать:

(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. Например. сделайте шаблон и напишите замену. Удачи.

...