ракетка - определение синтаксического класса с процедурой сопоставления с образцом - PullRequest
0 голосов
/ 02 июля 2018

Я пытаюсь определить синтаксический класс, соответствующий параметру, который является процедурой.

Я знаю, как сопоставлять идентификаторы, выражения, классы другого синтаксиса.

Это мой образец:

(define-syntax-class model-property
    #:description "a model property"
    #:attributes (name datatype guard)
    (pattern name:id
             #:with datatype #`null
             #:with guard #'(lambda (value) value)
             )
    (pattern [name:id #:datatype [datatype:id #:not-null] #:guard guard:expr])
    )

И я хотел бы заменить #:guard guard:expr на что-то вроде #:guard guard:procedure

Я экспериментировал с

(define-syntax-class model-property-guard
 #:description "a property guard"
(pattern guard:expr
         #:fail-when (procedure? #'guard)
         "property guard should be procedure."))

Возможно ли это? Как?

1 Ответ

0 голосов
/ 02 июля 2018

Макросы запускаются во время компиляции перед выполнением программы. Во время компиляции вы не можете знать, какое значение будет иметь выражение - информация просто не существует. (Вы можете теоретически проверить такую ​​вещь в языке со статической системой типов, но #lang racket динамически типизируется.)

Одна вещь, которую вы можете сделать, это заключить контракт в выражение, чтобы он вызывал ошибку времени выполнения, если контракт не совпадает. Синтаксический класс expr/c предоставляется для этой цели. Вы используете это так:

(begin-for-syntax
  (define-syntax-class model-property-guard
    #:description "a property guard"
    (pattern (~var guard (expr/c #'procedure?))
             #:with c #'guard.c)))

(define-syntax (m stx)
  (syntax-parse stx
    [(_ guard:model-property-guard)
     #'guard.c]))

Используя приведенные выше определения, запись (m add1) будет успешно производить #<procedure:add1>, а запись (m 1) завершится с ошибкой во время выполнения с нарушением контракта:

m: contract violation
  expected: procedure?
  given: 1
  in: procedure?

Обратите внимание, что расширение должно использовать guard.c в расширении! Атрибут c содержит модифицированное выражение, которое присоединяет контракт к значению, а прямое использование guard просто передает выражение без изменений, без присоединенного контракта.

Дополнительные примеры expr/c в действии см. В Контракты по подвыражениям макросов .

...