2017-05-25 11 views
4

スカラーまたはベクトル(この場合DiffSharpのDタイプとDVタイプ)で動作する数値コードを記述しようとしています。時々、私が使用できるようにしたいのいずれかので、私は彼らのために差別組合を定義した:差別化された共用体の演算子オーバーロード

type IBroadcastable = 
    | Scalar of D 
    | Vect of DV 

事業者の多くはすでにので、私はコードを追加記述IBroadcastableにそれらを使用するために、これらのタイプの両方のために、オーバーロードされていますこのように組合に:

static member Exp x = 
    match x with 
     | Scalar x -> Scalar (exp x) 
     | Vect x -> Vect (exp x) 

これは非常に冗長なようです。新しいオーバーロードを書く必要なく、私が組合でオペレータを使用できる方法はありますか?あるいは、私は異なるパターン(すなわち、差別化された組合ではない)を使用すべきですか?私はこのタイプを使用したいものの例:

let ll (y: IBroadcastable) (theta: IBroadcastable) = y*theta-(exp theta) 

*-は、それが自分自身を記述する必要があることは理にかなっていますが、expオペレータが簡単である、より複雑な行動(配列放送を)持っています、上記のように。これは関数である必要があります。なぜなら、y引数を部分的に適用し、DiffSharpでグラデーションを取得し、theta引数に関して最大​​化することができるようにしたいからです。

+0

組合がなぜ必要なのかわかりません。 'D'や' DV'の演算子を使っているのと比べると、今のところ手に取っているものは何ですか? –

+0

@FyodorSoikin私は、1つの引数がどちらかの型になる可能性のある関数を書くことを試みています。注:私はかなり新しいF#プログラマーですが、それがはっきりしない場合は。 –

+0

どのようにその機能を使用しますか?そしてそれはどのように実装されますか?なぜ機能の代わりに実装を使用することができませんでしたか? –

答えて

2

基本的に、抽象化を定義しているので、その抽象化の観点から操作を定義する必要があります。それはあなたのコードのどこかであなたに与えられる利便性によって相殺されなければならないコストです。

F#が特定のケースでボイラープレートをカットすることができるかどうか疑問に思うかもしれません。 functionキーワードを使用することは別として、実際には両方のブランチが実際には異なる作業をしているため、バインドされた変数xのタイプが異なり、異なるユニオンのケースでそれらをラッピングしています。あなたが本当に同じことをやっていた場合は、たとえば、そのように書くことができます:

type DU = 
| A of float * float 
| B of float * string 
with 
    static member Exp = function 
     | A (b, _) 
     | B (b, _) -> exp b // only write the logic once 
1

あなたのサンプル関数llは、実際にはもっと汎用的である - それは、それが使用する操作をサポートして何でも物事に取り組むことができますDまたはDVではありません。あなたがinlineを使用してそれを定義した場合は、両方の関数を呼び出すことができるようになります:

let inline ll y theta = y*theta-(exp theta) 

inline修飾子は、F#はとは異なり(関数を呼び出すときに必要なメンバーによって満たすことができる静的メンバ制約を、使用することができます通常のジェネリック関数は.NETランタイムが提供するものを使用してコンパイルする必要があります)。

DDVに固有の操作が必要ですが、expなどの汎用F#関数はありませんので、これはすべてのコードで機能しないと思います。静的メンバー制約を使用して実際にアクセスすることができますが、これは少し毛深いものになります。

DDV値の両方がstringを返すメンバーFooを持って、あなたが書くことができると仮定すると:

let inline foo (x:^T) = 
    (^T : (member Foo : string) x) 

let inline ll y theta = y*theta-(exp theta)+foo y 
1

あなたはこのような何かやっによって決まり文句を削減することができます。

type IBroadcastable = 
| Scalar of D 
| Vect of DV 

let inline private lift s v = function 
| Scalar d -> Scalar (s d) 
| Vect dv -> Vect (v dv) 

type IBroadcastable with 
    static member Exp b = lift exp exp b 
    static member Cos b = lift cos cos b 
    ... 

と場合をバイナリ演算子をサポートしたい場合は、対応するlift2を定義することができますが、バイナリオペラへの最初の引数torはScalarの値になり、2番目の値はVect(またはその逆)になります。そうでない場合、識別された共用体は適切な抽象化ではない可能性があります。

関連する問題