2014-01-12 2 views
1

Я хочу, чтобы иметь возможность написать вложенное выражение как это:Вложенные макросы в Ракетка

(AND/OR expr1 op1 expr2 AND/OR expr3 op2 expr4 and so on) 

Где И/ИЛИ, по существу, И или ИЛИ. Но я хочу иметь возможность писать бесконечное количество из них. Я использую define-syntax, чтобы попытаться это сделать, но я не уверен, как принимать бесконечное количество вложенных выражений.

Не возражайте против expr и op в моем примере, эту часть я могу справиться сам. Я только хочу знать, как принимать бесконечное гнездование.

Пример:

(SELECT somecolumns 
FROM sometable 
WHERE something 
AND/OR something 
AND/OR (something AND/OR something) 
AND/OR ...) 
+1

У Вас есть несколько входов образцов и образец ожидаемых результатов? –

+0

Я отредактировал сообщение с примером, который может сделать все более ясным. – Mathias

+2

Кажется, вам понравится писать ваши выражения типа '(AND/OR expr1 op1 expr2 (AND/OR expr3 op2 ...))'. Тогда ваши макросы, естественно, составят. В противном случае вы будете работать против синтаксиса s-expression, что усложнит ситуацию. –

ответ

2

Как говорит Asumu, в общем-то проще иметь дело с втор-выражений, по крайней мере, для того, чтобы обеспечить правильный приоритет оператора, но для некоторого простого сопоставления случаев шаблон из syntax-rulessyntax-parse и со) делает это легко, используя аргументы отдыха и рекурсивное соответствие:

#lang racket 
(define-syntax parse-args 
    (syntax-rules (AND) ; treat AND as a literal 
    [(_) 
    ; no more argument, return value: 
    '()] 

    [(_ (arg1 AND in-rst ...)) 
    ; Composed argument found, call parse-args recursively: 
    (parse-args arg1 AND in-rst ...)] 

    [(_ arg1 AND rst ...) 
    ; AND operator found, parse left side and rest 
    (list 'and 
      ; parse the argument (may be composed or not): 
      (parse-args arg1) 
      ; then parse the rest of the arguments: 
      (parse-args rst ...))] 

    [(_ arg) 
    ; in case the argument is not composed or does not contain AND, don't parse it 
    arg])) 

;; TESTS: 
(parse-args 'a AND ('b AND 'bb) AND 'c AND 'f) 
; -> '(and a (and (and b bb) (and c f))) 

(parse-args 'a AND ('b AND 'bb)) 
; -> '(and a (and b bb)) 

Однако, обратите внимание, что приведенный выше код может стать непрактичным при добавлении других операторов.

Edit: Вместе с выбора макроса:

(define-syntax SELECT 
    (syntax-rules (FROM WHERE) 
    [(_ select FROM from WHERE where ...) 
    (list 'Select select 'From from 'Where (parse-args where ...))])) 

; TEST: 
(SELECT 'somecolumns 
FROM 'sometable 
WHERE 'something1 
AND 'something2 
AND ('something3 AND 'something4) 
AND 'blop) 
; -> 
#;'(Select 
    somecolumns 
    From 
    sometable 
    Where 
    (and something1 
     (and something2 
       (and (and something3 something4) blop)))) 

Опять же, шаблон сопоставления позволяет резать список в нужный момент, чтобы получить аргументы отдыха

+0

Я определенно понимаю, почему это правдоподобный способ, но можно ли комбинировать это с синтаксисом вышеприведенного оператора (SELECT FROM WHERE)? Извините, если я немного отстаю отсюда, но ракетка все еще запутывает меня, поскольку я новичок в этом. – Mathias

+0

Я отредактировал свой ответ, чтобы добавить макрос SELECT, но если вам непонятно, возможно, это не лучшее упражнение для начала. Я подозреваю, что вы еще не устраиваете рекурсию. Если это так, вам, вероятно, следует избегать макросов и продолжать изучение рекурсивных функций и аргументов отдыха. – Metaxal

+0

Большое спасибо. Просто мне не нравятся макросы в Rackets, я очень хорошо знаком с рекурсией с других функциональных языков. Опять же, спасибо! – Mathias

Смежные вопросы