Guile `синтаксические правила`: неуместный эллипс в форме; Как написать этот макрос с двумя эллипсами?
Я пытаюсь более или менее воссоздать 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 ответ
Это возможно с помощью вспомогательного макроса, чтобы выполнить рекурсию, необходимую для нахождения 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))