Взаимно ссылающиеся случаи в размеченных союзах разрешены в F #?

Не удается скомпилировать следующий размеченный союз:

type Expression =
  | Identifier of string
  | Integer of int
  | Assignment of Identifier * Expression

с показанной ошибкой

The type "Identifier" is not defined.

по последнему союзному делу.

Я пытался пометить Expression атрибутом rec, но это не помогло.

Есть ли обходной путь для этого? Еще лучше, является ли упомянутая причина причиной моей проблемы?


person devoured elysium    schedule 26.08.2011    source источник


Ответы (2)


Вы не можете сделать это. Внутри Union нельзя ссылаться на другой элемент Union.

Так должно быть:

type Expression =
  | Identifier of string
  | Integer of int
  | Assignment of Expression * Expression

Так что, когда вы анализируете объединение присваивания, вы можете поместить туда проверку того, что первое выражение в кортеже должно быть идентификатором.

person Ankur    schedule 26.08.2011
comment
Аргх :(. Теперь обычный вопрос: почему мы не можем это сделать? - person devoured elysium; 26.08.2011
comment
Ваш ответ правильный, но я думаю, что он должен использовать | Assignment of string * Expression, потому что 4 <- 5 не имеет смысла. - person Ramon Snir; 26.08.2011
comment
@devoured Идентификатор является функцией типа (строка -> Выражение), а не типом. Выражение или строка являются типами. - person Ramon Snir; 26.08.2011
comment
Внутри Union нельзя ссылаться на другой элемент Union. Это звучит так, как если бы вы попытались сослаться на Identifier как на тип откуда-то за пределами объединения, это сработало бы (хотя я уверен, что вы имели в виду не это). Итак, чтобы быть совершенно ясным: как правильно указывает Рамон, Identifier не является типом, вы не можете использовать его в любом контексте, где требуется тип. Вы не можете использовать его как тип аргумента функций, тип возвращаемого значения для функций или тип переменной. Его можно использовать только для сопоставления значений выражения с образцом или для создания значений выражения. - person sepp2k; 26.08.2011
comment
@Ramon: По крайней мере, в моем конкретном случае предложение Анкура вполне приемлемо. Я пишу простой компилятор, и это только фаза синтаксического анализа. позже, на этапе семантического анализа, я могу уловить эти несоответствия. - person devoured elysium; 26.08.2011

Похоже, вы действительно хотите

| Assignment of string * Expression

или альтернативно

type Id = Id of string
type Expression =
    | Identifier of Id
    | Integer of int
    | Assignment of Id * Expression

если вам нужен дополнительный номинальный тип для всех идентификаторов.

Лучше всего по возможности исключать бессмысленные значения в системе типов (бессмысленные состояния не должен быть представлен), поэтому я бы избегал Expression в левой части присваивания, если это не нужно вашему языку.

В любом случае причина, по которой это запрещено, заключается в том, что Identifier не является типом (а Expression является).

person Brian    schedule 26.08.2011