2016-07-06 4 views
1

次のコードでは、変数の型を使用して最終的に関数に渡される汎用変数としてテンプレート化されたクラスをインスタンス化したいと思いますが、F#テンプレートでのコンパイル時の導出型の使用

type saveXY<'a when 'a:comparison> (x:'a,y:'a) = 
    member this.X = x 
    member this.Y = y 
    member this.lessThan() = this.X < this.Y 

[<EntryPoint>] 
let main argv = 

    let x1 = 3 
    let y1 = 7 
    let saver1 = new saveXY<int>(x1,y1)   // Good 
    printfn "%A" (saver1.lessThan()) 

    let x2 = 3.0 
    let y2 = 7.0 
    let saver2 = new saveXY<float>(x2,y2)   // Good 
    printfn "%A" (saver2.lessThan()) 

    let saver3 = new saveXY<x2.GetType()> (x2,y2) // No Good, see errors 

    0 

ただし、以下saver3のために私は(と私はFS1241上の情報を見つけるカント)を取得:

...\Program.fs(23,39): error FS0010: Unexpected symbol '(' in type arguments. Expected ',' or other token. 
...\CompareProblem\Program.fs(23,39): error FS1241: Expected type argument or static argument 

あなたはsaveXY上のテンプレートを削除した場合saver1が012の原因として、そしてsaver2にエラーがありますクラスの引数はintに制約されます。

私はxとyを単にobjと宣言して実験しましたが、これはうまくいきません。私は問題がこれは単純に可能ではないということだと思っています。クラス引数の型がジェネリックである場合は、最初に使用されたときに派生したものです。 一方、私は何かを逃しているかもしれません。

F#の型テンプレート引数として、コンパイル時に決定可能な変数ベースの型を使用する方法はありますか?一般的な値を扱う/格納することができる型を作成する別の方法がありますか?

UPDATE

type saveXY<'a when 'a:comparison> (x:'a, y:'a) = 
    member this.X = x 
    member this.Y = y 
    member this.lessThan() = this.X < this.Y 

[<EntryPoint>] 
let main argv = 

    let x1 = 3 
    let y1 = 7 
    let saver3 = new saveXY<_> (x1,y1) // works, 'a is int 
    printfn "%A" (saver3.lessThan()) 

    let x2 = 3.0 
    let y2 = 7.0 
    let saver3 = new saveXY<_> (x2,y2) // works, 'a is float 
    printfn "%A" (saver3.lessThan()) 

    System.Console.ReadKey() |> ignore // wait for a key 
    0 

しかし、なぜ、私はクラス型をテンプレートする必要がある、として:あなたがクラスをテンプレートとそしてちょうどそれが動作するインスタンス化する<_>を使用する場合リーの提案から、これは、作品私は上記の提案?私が単に(Iは、関数の場合と同じように)使用することはできませんなぜ私はそう<_>を使用する場合、コンパイラはとにかく種類を推定していることと思われる:

type saveXY(x, y) = // x and y are generic, no? They only require comparison, yes? 
    member this.X = x 
    member this.Y = y 
    member this.lessThan() = this.X < this.Y 

[<EntryPoint>] 
let main argv = 

    let x1 = 3 
    let y1 = 7 
    let saver3 = new saveXY (x1,y1) // works 
    printfn "%A" (saver3.lessThan()) 

    let x2 = 3.0 
    let y2 = 7.0 
    let saver3 = new saveXY (x2,y2) // But this FAILS with error FS0001 
    printfn "%A" (saver3.lessThan()) 

    System.Console.ReadKey() |> ignore // wait for a key 
    0 
+1

「x2」と「y2」の型を静的に知っていますが、このような型パラメータを指定することはできません。したがって、ユースケースは明確ではありません。 – Lee

+2

あなたがしようとしていることをあまり明確にはっきりさせていません:コンパイル時には知られていない汎用引数を使ってクラスをインスタンス化するコードを作成しようとしていますか? that_ "を使用して、コンパイラに理解させてもらえますか? –

+0

それは:_simply "どのような型x2が、それを使用してください"と言うと、コンパイラはそれを理解していますか?_ case - 上記の例では、 'saver3'をfloatテンプレート型でインスタンス化したいと思います。 'x2'は浮動小数点です。実際のコードでは、x2はジェネリック型の関数の引数になりますが、関数はさまざまなコンパイル時の型でインスタンス化されます – user1857742

答えて

2

あなただけのコンパイラがの型を推論したい場合あなたが使用することができ、一般的なパラメータ:F#は、実行時に知られているタイプの汎用コードをインスタンス化するための任意の組み込みメソッドを持っていない

let saver3 = new saveXY<_>(x2, y2) 

または

let saver3 = saveXY(x2, y2) 
+0

2番目の形式は機能しませんが、最初の形式は更新されます - – user1857742

+0

@user1857742 - F#のどのバージョンあなたは使っていますか? 2番目のフォームは、F#4を必要とする可能性があります。 – Lee

+0

私はその3.1 - Visual Studio 2013で考えています – user1857742

2

。リフレクションを使用していつでも行うことができますが、それはあまり有用ではありません。リフレクションを使用してそれを作成すると、実際には価値があまりありません。

例のためには、別のインターフェースにLessThanを移動できる:引数を表すSystem.Typeobj値が与えられ、あなたがリフレクションを使用して、実行時にSaveXY<T>のインスタンスを作成することができ

type ILessThan = 
    abstract LessThan : unit -> bool 

type SaveXY<'T when 'T:comparison> (x:'T,y:'T) = 
    member this.X = x 
    member this.Y = y 
    interface ILessThan with 
    member this.LessThan() = 
     printfn "Comparing values of type: %s" (typeof<'T>.Name) 
     this.X < this.Y 

typeof<T>は、与えられたSystem.Typeている:ここで

let createSaveXY typ x y = 
    let typ = typedefof<SaveXY<_>>.MakeGenericType [| typ |] 
    typ.GetConstructors().[0].Invoke([| x; y |]) :?> ILessThan 

は、これがどのように機能するかの例です。

let lt = createSaveXY (typeof<float>) (box 3.0) (box 7.0) 
lt.LessThan() 

しかし、私が先に言ったように、これはまれに有用であり、それは、超効率的ではない - ので、むしろこれをコピーするよりも、あなたが解決しようとしている問題を記述してみてください - よりよい解決策は、おそらくそこにあります。

+0

詳細な回答ありがとうございます - 私はランタイムにしか知られていないタイプのクラスをインスタンス化したくありませんが、機能。 – user1857742

関連する問題