6

私はこのようなものを書きたいです:

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定義自体はOKです。

同じケースを使用して、次のような間接参照のレベルを追加しないようにします

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

Exp定義で。ここでは非常に基本的なものが欠けているように感じます。

私が持っている理由は、式の生成を容易にするため、2を(2つのフロートではなく)NumExpに「プラグイン」できるようにしたいからです。ExpDotExp

編集:私が本当に知りたかったのは、2つのDUの2つのケースを同じエンティティ(Exp「含む」のようなものNumExp)として扱うことができるかどうかです。私は今気づきExp.NumNumExp.Num完全に別の存在です。Tomasは、以下の2つのケースを区別するための優れた方法を提供します。

4

4 に答える 4

14

ケースの名前が競合する2つの識別された共用体がある場合は、識別された共用体のケースの完全修飾名を使用できます。

 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) -> // ...
于 2010-07-07T13:32:45.470 に答える
2

それが可能な場合(たとえば、OCamlでポリモーフィックバリアントを使用する場合)、それを使って多くのことを行うことができますが、(悲しいことに)F#にはこの言語機能がないため、現在、共用体型を使用して必要なものを表現できません。ただし、代わりにOOPの使用を検討することもできます...

于 2010-07-08T23:33:37.417 に答える
2

代わりにインターフェースを使用できます。これにより、構文上のオーバーヘッドが少し追加されますが、これを行うための最良の方法です。

type IExp = interface end

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

// This function accepts both NumExp and Exp
let f (x:IExp) = match x with
    | :? NumExp as e -> match e with
        | Num v -> "Num"
    | :? Exp as e -> match e with
        | Dot (e1,e2) -> "Dot"
        | Op (op,e1,e2) -> "Op"
    | _ -> invalidArg "x" "Unsupported expression type"

// This function accepts only NumExp
let g = function
    | Num v -> "Num"
于 2015-02-16T17:07:57.487 に答える
-1

ただの観察:なぜあなたはこのように構築された組合が必要なのですか?

私は2つのオプションのいずれかを選択したでしょう:

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

この2番目のケースでは、関数

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

あなたが今の1つの定義を持っているように動作しますNumExp

于 2010-07-07T22:25:38.930 に答える