Ракетка - Макро - Определить функцию
Итак, я хочу создать макрос, который облегчит написание функций, которые принимают s-выражение и список в качестве входных данных и что-то делают, когда одно из s-выражений в списке совпадает с s-выражением во входных данных., Я заметил, что многие из этих функций имеют одинаковый внешний вид.
Итак, я написал это:
(define-syntax (ember stx)
(syntax-parse stx
[(ember name terminal match recurse) #'(define name (lambda (s l)
(cond
[(null? l) terminal]
[(eq? (car l) s) match]
[else recurse])))]))
(ember member #f #t (match s (cdr l)))
К сожалению, это не работает, потому что s является несвязанным идентификатором. Я попытался заключить его в кавычку, а затем поместить в макрос eval, но это также привело к появлению несвязанного идентификатора.
Итак, я переписал свой код следующим образом, и он работает:
(define-syntax (ember stx)
(syntax-parse stx
[(ember name terminal match recurse) #'(define name (lambda (s l)
(cond
[(null? l) (terminal s l)]
[(eq? (car l) s) (match s l)]
[else (recurse s l)])))]))
(ember member (lambda (x y) #f) (lambda (x y) #t) (lambda (x y) (match x (cdr y))))
Но, к сожалению, если мое определение соответствия становится таким сложным, кажется, проще просто скопировать функцию-член и создать новые функции того же рода, отредактировав места, где параметры терминала, соответствия и рекурсии идут вручную.
Есть лучший способ сделать это?
2 ответа
Вы должны использовать параметры синтаксиса вместо datum-> синтаксис:
(define-syntax-parameter s (syntax-rules ()))
(define-syntax-parameter l (syntax-rules ()))
(define-syntax-rule
(ember name terminal match recurse)
(define name
(lambda (s* l*)
(syntax-parameterize ([s (make-rename-transformer #'s*)]
[l (make-rename-transformer #'l*)])
(cond
[(null? l) terminal]
[(eq? (car l) s) match]
[else recurse])))))
(ember member #f l (member s (cdr l)))
(member 'a '(1 2 a 3))
; -> '(a 3)
Посмотрите Поддержание этого Чистым с Синтаксическими Параметрами для деталей относительно того, почему.
Вы не можете взять s
а также l
из воздуха, но убедитесь, что они совпадают с вашими данными. Это делает это:
(define-syntax (ember stx)
(syntax-parse stx
[(ember name terminal match recurse)
(with-syntax ([s (datum->syntax stx 's)]
[l (datum->syntax stx 'l)])
#'(define name (lambda (s l)
(cond
[(null? l) terminal]
[(eq? (car l) s) match]
[else recurse]))))]))
(ember member2 #f l (member2 s (cdr l)))
(member2 'a '(1 2 a 3))
; ==> (a 3)