2015-05-24 8 views
1

Опасается ли мошенник защитой шаблонов?Защитные ограждения от ураганов

Я пытаюсь заказать подвыражения по сборке:

data Expr = and(Expr l, Expr r) | ... ; 
Expr and(l, r) | r < l = and(r, l); // fictional syntax for "r < l" guard 

Если охранники не поддерживаются, что самый лучший способ реализации выше?

ответ

1

Просто для упрощения вещей я использовал int как тип для l и r сперва. То, что вы хотите сделать что-то вроде следующего:

rascal>data Expr = and(int l, int r); 
ok 

rascal>Expr and(int l, int r) = and(r,l) when r < l; 
Expr (int, int): rascalfunction() 

rascal>and(5,6); 
Expr: and(5,6) 

rascal>and(6,5); 
Expr: and(5,6) 

Если вы создаете функцию с тем же именем, что и конструктор, который возвращает тип данных, определяемый вами (например, Expr), это позволит вам сделать этот вид канонизации. В предложении when говорится, что применяется только при выполнении условия. У вас может быть более сложное условие, поэтому, если бы у вас было Expr, вместо этого в качестве типа полей вы могли бы иметь такую ​​функцию, как eval, которая фактически оценивает выражение и возвращает результат. Частичный пример этого (что предполагает у вас есть только один уровень вложенности) заключается в следующем:

rascal>data Expr = number(int n) | and(Expr l, Expr r); 
ok 

rascal>int eval(number(int n)) = n; 
int (Expr): rascalfunction() 

rascal>Expr and(Expr l, Expr r) = and(r,l) when eval(r) < eval(l); 
Expr (Expr, Expr): rascalfunction() 

rascal>and(number(5),number(6)); 
Expr: and(
    number(5), 
    number(6)) 

rascal>and(number(6),number(5)); 
Expr: and(
    number(5), 
    number(6)) 

Чтобы использовать when, вы должны использовать это выражение вид функции, где Вы состоите = знак и возвращаемое значение. Если у вас есть более сложные вычисления в канонизации, вы можете вместо этого сделать что-то вроде следующего:

Expr and(int l, int r) { 
    if (r < l) { 
     return and(r,l); 
    } else { 
     fail; 
    } 
} 

Это по существу делает то же самое. Если условие выполнено, возвращается новая версия and. Если условие не выполняется, fail используется для указания того, что в действительности мы не хотим, чтобы применить эту функцию, поэтому начальное значение будет возвращено:

rascal>and(5,6); 
Expr: and(5,6) 

rascal>and(6,5); 
Expr: and(5,6) 
+0

'when' и' fail' являются именно то, что мне нужно , благодаря. –

+1

Я бы рекомендовал всегда использовать 'fail и; 'вместо plain' fail', потому что 'fail' лексически привязан к самому внутреннему ошибочному контексту (например, к if-ветви или к телу цикла for). В случае 'else' это необязательно, так как внутренний наиболее ошибочный контекст является самой функцией. 'fail' с меткой позволяет вам перейти к внешнему ошибочному контексту (в данном случае' 'и' функция '). – jurgenv