2017-09-23 2 views
1

クラスコンストラクタを呼び出すクラスbeforeの静的メンバーを呼び出す必要があります。クラスはインターフェイスを実装しており、後でafter the object is constructedに同じ静的メンバーを呼び出す必要があります(多態的に)。静的メソッドに多態的にアクセスできますか?

私はいくつかの言語は、1ドットの前にインスタンス名を持つ静的メソッドにアクセスすることができ、

myClassInstance.staticMethod 
のようなもの

F#があるため、クラスがインタフェースから継承する場合は特に、それを許可していないようだと信じてインターフェイスに静的メソッドを含めることはできません。

次のコードは、問題を例示:

module Types 

type IMult = 
    abstract member Something : float 
    abstract member MultBy : float -> float 

open Types 

type Point(x: float) = 
    interface Types.IMult with 
     member this.Something with get() = x 
     member this.MultBy (x: float) = 
      (this :> IMult).Something * x 

    static member public foo x = x + 3.0 

let myPointConstructorArgument = Point.foo 5.0 
let pt = Point(myPointConstructorArgument) 

printfn "%f" <| (pt :> IMult).MultBy 10.0 // OK: 80.0 

let bar (instnc: IMult) = instnc.foo // Error: foo not defined 
let pt0 = Point(bar pt 6.0) // No good: error above 

私の質問は:それはどういうわけか、オブジェクトのクラスを取得し、抽象メソッドを呼び出すことは可能でしょうか?

私は次のことを試してみました:

let ptType = pt0.GetType() 
let mtd = ptType.foo // Error: foo not defined 
let mtd = ptType.GetMethod("foo") // Ok, but not what I need, see below 
let i2 = mtd 3.0 // Error: mtd is not a function 

これを実行する別の方法のための任意の提案を?

+0

あなたが拡張メソッドとして定義することができますが、なぜあなたはインスタンスとそれを呼び出す必要がありますか?インスタンス自体の影響を受けていないようです。 – Gustavo

+1

静的に解決された型の制約を見てください。 –

+0

@Gustavo - インスタンスで呼び出す必要はありません。確かにインスタンスに依存しません(静的なので)。私はクラス名で呼び出すことができなかったので、インスタンスで呼び出すことを考えました。呼び出し時にクラスがいくつかの選択肢のいずれかになる可能性があったからです。 F#をインスタンスから呼び出すと、問題は解決されます。 – Soldalma

答えて

2

「タイプクラス」や「目撃者」は、まだサポートされていない言語機能ですが、この機能の実装を追跡するthis issueは非常にアクティブです。
現在、F#には、多態性のアクセスを得るためのいくつかの方法があります。

1)インターフェイスを介したインスタンスメンバ。インスタンスを構築する前にアクセスする必要があるので、多型メンバーを直接IMult型に置くことはできないようですが、「型」のインタフェースを作成し、それを追加の引数として渡すことができますこれは)型クラスは、「カバーの下に」どのように動作するかに非常によく似ています

//your "trait" 
type IFoo<'a> = 
    abstract member Foo : float -> float 

//your "witness", defines what "Foo" means for the "Point" type. Other witnesses could define what "Foo" means for other types. 
let fooablePoint = { new IFoo<Point> with member this.Foo x = Point.foo x } 

let bar (fooable:IFoo<'a>) = fooable.Foo //this isn't really necessary anymore, but illustrates that a function can use a polymorphic "static" function, given a witness 
let pt0 = Point(bar fooablePoint 6.0) 

2)静的メンバ制約(上記のコメントで指摘したように):一方で

let inline bar (pt:^a) x = 
    (^a : (static member foo : float -> float) x) 

これは型の静的メンバーにポリモーフィックにアクセスする能力を与えますが、過度に使用されるaccording to fsharp.org。構文はかなり不透明で、解読が難しい場合があります。また、インライン関数の場合にのみ機能するため、ユビキタスで使用すると、アプリケーションのパフォーマンスが著しく低下する可能性があります。これはすでにタイプ^aのインスタンスがある場合にのみ機能するので、この解決法もあなたのためには機能しない可能性があることに注意してください。

3)ただ、何でも他の機能へのfoo関数を渡すことが必要です。

let bar (foo:float -> float) x = foo x // type annotations wouldn't be necessary, and just provided for clarity 
let pt0 = Point (bar Point.foo 6.0) 

4)(以下のコメントで説明):IMultの内側にあなたはまだ内のその後

abstract member foo: float -> float 

を定義することができますPoint、ちょうど持っている

interface Types.IMult with 
    member this.Foo x = Point.foo x 

これはyあなたが望むすべてのもの。そのメンバーは、Pointタイプの静的メンバーであるインスタンスメンバーIMultに存在するので、それはもはや実際には "静的多型"ではありませんが、あなたの目標を達成するかもしれません。

+0

これは私の頭の上に少しですが、私は1と3を見ました(私は2で見ていますが、後でもっと複雑に見えます)。どちらの場合も、コード内に「ポイント」という言葉を使用しました。しかし、実行時に私はどのクラスを使用しているのか分からず、PointまたはIMultを継承する別のクラスになる可能性があります。したがって、これらの2つの提案(1と3)は問題を解決していないようです。何か不足していますか? – Soldalma

+1

@ソルダルマはい、あなたはそれがより多相的であることを望むかもしれません。あなたは 'pt'変数と同じレベルで定義された多相関数/インタフェースを作成する必要があります。たとえば、オプション1の場合、次のように定義します。 'fooable:IFoo <'a> = fooablePoint'を' pt'と同時に実行すると、それらは一緒になります( 'poo'の代わりに' fooable'を 'bar'に渡します)。オプション#2では、 'pt'と同じ場所に' let foo:float - > float = Point.foo'を定義します。これも 'pt'と並んでいます。タイプクラスなしで 'pt'で"束ねる "方法はありません。 –

+1

@Soldalma、 'IMult'の内部で' abstract member foo:float - > float'を定義して、 'Point'内に' this.Foo x = Point.foo x 'これはあなたに必要なものすべてを与えるかもしれません。そのメンバは 'Point'型の静的メンバと' IMult'のインスタンスメンバとして存在しますが、もう "静的多型"ではありません。 –

0

私は上記の "1"と一緒に行くでしょう、タイプクラスにぶら下がってはいけません - 彼らは存在しないし、何らかの形で、とにかく理想的ではありません。

私にとって、抽象概念が不足しています。ファクトリやドメインエンティティのようなもので、静的メソッドをキャプチャして明示的に渡します。

type MultDomain<'a when 'a :> IMult> = 
    abstract member foo : float -> float 

type PointDomain = 
    interface MultDomain<Point> with 
     member o.foo x = x + 3.0 

(制約「':> IMultは」あなたのコンテキスト内で必要な、しかし、あなたは、このインターフェイスで作成するためにまだあるオブジェクトの型を使用することができることを示していない)

ので、答えは "はい、多態的に" ...または多分 "を呼び出すことができるいくつかの型のインスタンスメソッドにマップする限り、それらを多態的に呼び出すことができるいくつかの型のインスタンスメソッドにマップすることができます"

(個人的に私は、静的メソッドを持っていることはありません、とさえコンストラクタを避ける!)

関連する問題