Общие случаи в дизъюнктных объединениях F#

Я хочу записать что-то вроде этого:

type NumExp = Num of float

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

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

Компилятор жалуется на конфликт между NumExp и Exp в getValue. Даже следующие сбои:

let getValue (nn : NumExp) = match nn with | Num(n) -> n

Существует ли способ использовать тот же случай в обоих дизъюнктных объединениях, который работает с функциями? Сами определения DU в порядке.

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

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

в Exp определение. Я чувствую, что пропускаю что-то очень простое здесь.

Причина я имею NumExp это, я хочу смочь 'включиться' 2 Exps в a Dot (а не 2 плавания), потому что это делает генерирующиеся выражения легче, но они не могут быть никем Exp, просто числовой.

Править: то, что я действительно хотел знать, - можно ли эти два случая в двух DUs было рассматривать как тот же объект (отчасти как Exp "включая" NumExp). Я понимаю теперь Exp.Num и NumExp.Num абсолютно отдельные объекты. Tomas обеспечивает хороший способ отличить эти два случая ниже.

6
задан Mau 8 July 2010 в 11:00
поделиться

3 ответа

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

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

Более полный пример будет выглядеть так:

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

Здесь всегда используются полностью определенные имена, которые вероятно, хорошая идея, если имена достаточно простые и есть противоречивые случаи (что может привести к путанице).

РЕДАКТИРОВАТЬ: Что касается совместного использования кейсов - автоматического способа сделать это нет, но вы можете иметь кейс в вашем Exp , который просто включает значения NumExp . Например, так:

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

При написании функции eval вы должны затем написать (обратите внимание, что у нас больше нет проблемы с конфликтами имен, поэтому нам не нужны полностью определенные имена):

| NumExp(Num f) -> f
| Op(op, e1, e2) -> // ...
14
ответ дан 8 December 2019 в 13:43
поделиться

Когда это возможно (например, использование полиморфных вариантов в OCaml), вы можете многого добиться, но (к сожалению) F# не имеет такой возможности языка, поэтому в настоящее время он не способен выразить то, что вы хотите, используя типы объединения. Однако, вы можете рассмотреть возможность использования ООП вместо этого...

2
ответ дан 8 December 2019 в 13:43
поделиться

Просто наблюдение: зачем вам профсоюзы, построенные таким образом?

Я бы выбрал один из двух вариантов:

type NumExp = Num of float

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

, который является более простым, или

type NumExp = Num of float

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

В данном случае ваша функция

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

работает так, как у вас есть одно определение NumExp сейчас.

-1
ответ дан 8 December 2019 в 13:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: