+10  A: 

If you have two discriminated unions with conflicting names of cases, you can use fully qualified name of the discriminated union case:

 let getValue (NumExp.Num(n)) = n  

A more complete example would look like this:

let rec eval = function
  | Exp.Num(f) -> f
  | Exp.Dot(NumExp.Num(f1), NumExp.Num(f2)) -> 
      // whatever 'dot' represents
  | Exp.Op(op, e1, e2) ->
      // operator

This always uses fully qualified names, which is probably a good idea if the names are simple enough and there are conflicting cases (which could lead to a confusion).

EDIT: Regarding sharing of cases - there is no automatic way of doing that, but you could have a case in your Exp that simply includes values of NumExp. For example like this:

type NumExp =
  | Num of float 

type Exp = 
  // first occurrence of NumExp is just a name, but F# allows us to reuse 
  // the name of the type, so we do that (you could use other name)
  | NumExp of NumExp  
  // other cases

When writing eval function you would then write (note that we no longer have the issue with name clashes, so we don't need fully qualified names):

| NumExp(Num f) -> f
| Op(op, e1, e2) -> // ...
Tomas Petricek
Thanks Tomas, the disambiguation works wonders. What I was asking, though was more like 'can the two cases in the two DUs be treated as the same entity?', or in other words, 'can Exp "include" NumExp?'. But from your answer, the answer is no. Thanks!
Mau
@Mau: I added some information about sharing of the cases between different discriminated unions. It is not possible, but you can include one in the other.
Tomas Petricek
@Tomas: thanks, that's exactly what I had done :-)
Mau
A: 

Just an observation: Why do you need the unions constructed this way?

I would have chosen one of two options:

type NumExp = Num of float

type Exp =
    | Num of float
    | Dot of float * float
    | Op of string * Exp * Exp

which is the more simple, or

type NumExp = Num of float

type Exp =
    | NumExp
    | Dot of float * float
    | Op of string * Exp * Exp

In this second case, your function

let getValue (Num(n) : NumExp) = n

works as you have one definition of NumExp now.

Muhammad Alkarouri
Thanks Muhammad. The first solution is excluded in the question above (harder to deal with in the rest of the code).The second solution is syntactically correct and semantically what I would like, but produces a different data structure from what I need (`Exp.NumExp` is just an empty case, not a field of type `NumExp`).
Mau
+2  A: 

When that is possible (e.g. using polymorphic variants in OCaml), you can do a lot with it but (sadly) F# does not have this language feature so it is currently incapable of expressing what you want using union types. However, you might consider using OOP instead...

Jon Harrop