Guile `синтаксические правила`: многоточие в форме;Как написать этот макрос с двумя эллипсами? - PullRequest
3 голосов
/ 17 апреля 2019

Я пытаюсь, более или менее, воссоздать конструкцию let с помощью syntax-rules, но, похоже, она отключается при использовании двух эллипсов.

Я попытался записать это так:

(define-syntax if-let
  (syntax-rules ()
    [(_ (([binding        value]  ...)
         ([binding2 funct value2])
         ([binding3       value3] ...)) then else) (let ([binding  value]  ...
                                                         [binding2 value2]
                                                         [binding3 value3] ...)
                                                     (if (funct binding2) then else))]))

Я полагал, что отчетливый паттерн в середине [binding2 funct value2] мог бы обеспечить четкое разделение с точки зрения паттерна того, когда первый паттерн закончился, и когда начался второй, но я продолжаю возвращать ошибку в название.

Ожидаемый результат - быть в состоянии сделать что-то вроде

(if-let ([var1                  1]
         [diff null? '(1 2 3 4 5)]
         [var2                  2])
    var1
  var2)

и получить обратно 2, но иметь возможность иметь столько var с до и после diff, сколько требуется удаленно, поэтому порядок используемых переменных, в конечном счете, не имеет значения.

Я что-то упускаю из виду? И реально ли этот шаблон сделать с помощью гигиенических макросов? Спасибо за любую помощь!

1 Ответ

0 голосов
/ 18 апреля 2019

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

(if-let-helper processed-bindings processed-conditions input-binding-conditions then else)

Как только он повторяется, он передает информацию из input-binding-conditions в processed-bindings и processed-conditions, останавливаясь, когда input-binding-conditions пусто.

(define-syntax if-let-helper
  (syntax-rules ()
    [(_ ([bnd val] ...) (cnd ...) () then else)
     (let ([bnd val] ...)
       (if (and cnd ...) then else))]
    [(_ ([bnd val] ...) (cnd ...) ([binding value] . rest) then else)
     (if-let-helper ([bnd val] ... [binding value]) (cnd ...) rest then else)]
    [(_ ([bnd val] ...) (cnd ...) ([binding funct value] . rest) then else)
     (if-let-helper ([bnd val] ... [binding value]) (cnd ... (funct binding))
                    rest then else)]))

(define-syntax if-let
  (syntax-rules ()
    [(_ (binding-funct-value ...) then else)
     (if-let-helper () () (binding-funct-value ...) then else)]))

Используя его:

> (if-let ([var1                  1]
           [diff null? '(1 2 3 4 5)]
           [var2                  2])
    var1
    var2)
2

Чтобы объяснить это, я расскажу, как этот пример обрабатывает каждое предложение. Первоначально он превращается в этот if-let-helper вызов:

(if-let-helper
  ()
  ()
  ([var1                  1]
   [diff null? '(1 2 3 4 5)]
   [var2                  2])
  var1
  var2)

Первые два списка начинаются пустыми, потому что он еще ничего не обработал.

(if-let-helper
  ([var1                  1])
  ()
  ([diff null? '(1 2 3 4 5)]
   [var2                  2])
  var1
  var2)

На этом этапе он обработал первое предложение и добавил пару значений привязки в первый список «обработанных привязок». Однако в первом предложении не было funct, поэтому оно не добавило условие во второй список «обработанных условий».

(if-let-helper
  ([var1                  1]
   [diff       '(1 2 3 4 5)])
  ((null? diff))
  ([var2                  2])
  var1
  var2)

В этот момент он обработал первые два предложения и добавил условие (null? diff) во второй список, поскольку во втором предложении он увидел funct.

(if-let-helper
  ([var1                  1]
   [diff       '(1 2 3 4 5)]
   [var2                  2])
  ((null? diff))
  ()
  var1
  var2)

В этот момент он обработал все три предложения, поэтому он попадает в базовый вариант и преобразуется в финальные let и if:

(let ([var1                  1]
      [diff       '(1 2 3 4 5)]
      [var2                  2])
  (if (and (null? diff))
      var1
      var2))
...