2

The following discriminated union fails to compile:

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

with the shown error being

The type "Identifier" is not defined.

on the last union case.

I've tried tagging Expression with the rec attribute but that seems of no avail.

Is there a work-around for this? Better yet, is the referred reason the cause of my trouble?

devoured elysium
  • 101,373
  • 131
  • 340
  • 557

2 Answers2

10

It sounds like you actually want

| Assignment of string * Expression

or alternatively

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

if you want an extra nominal type for all identifiers.

It is best to exclude meaningless values in the type system when possible (meaningless states should not be representable), which is why I'd avoid Expression on the left hand side of an assignment if your language doesn't need that.

In any case, the reason it's not allowed is because Identifier is not a type (Expression is).

Community
  • 1
  • 1
Brian
  • 117,631
  • 17
  • 236
  • 300
4

You cannot do that. Inside the Union you cannot refer to another Union element.

So it should be:

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

So that when you parse the assignment union you can put a validation there that the first Expression in the tuple should be Identifier.

Ankur
  • 33,367
  • 2
  • 46
  • 72
  • Argh :(. Now the usual question: why can't we do it? – devoured elysium Aug 26 '11 at 07:02
  • 2
    Your answer is the right one, but I think he should use `| Assignment of string * Expression`, because `4 <- 5` doesn't make sense. – Ramon Snir Aug 26 '11 at 07:03
  • 1
    @devoured Identifier is a function of type (string -> Expression), not a type. Expression or string are types. – Ramon Snir Aug 26 '11 at 07:04
  • 1
    "Inside the Union you cannot refer to another Union element." That kind of makes it sound as if you tried to refer to Identifier as type from somewhere outside the union, it would work (though I'm sure that's not what you meant). So to be perfectly clear: Like Ramon correctly points out, `Identifier` is not a type, you can't use it in any context where a type is required. You can't use it as an argument type of functions, a return type for functions or the type of a variable. The only places you can use it are to pattern match Expression values or to create Expression values. – sepp2k Aug 26 '11 at 07:18
  • @Ramon: At least in my particular case, Ankur's suggestion is perfectly acceptable. I'm writing a simple compiler, and this is just the parsing phase. later on, in the semantic analysis phase, I can catch those inconsistencies. – devoured elysium Aug 26 '11 at 07:33