3

次のように、オーバーロードされた演算子を定義しようとして|+|います。

let inline ( |+| ) (m1 : #IMeasurable) (m2 : #IMeasurable) = m1.Measure + m2.Measure

問題は、次のようなことができないことです。

let three = m1 |+| m2 |+| m3

case に対して演算子|+|が定義されていないため(m1 : int) (m2 : #IMeasurable)です。この演算子をオーバーロードするか、静的型制約を使用して上記の式を可能にする方法はありますか? IMeasurableこれを可能にするために (編集できる)変更する方法はありますか? 上記の式が機能することを可能にする何か他のものはありますか?

ありがとうございました。

4

2 に答える 2

11
type Overloads = Overloads with
    static member ($) (Overloads, m1: #IMeasurable) = fun (m2: #IMeasurable) -> m1.Measure + m2.Measure 
    static member ($) (Overloads, m1: int) = fun (m2: #IMeasurable) -> m1 + m2.Measure

let inline ( |+| ) m1 m2 = (Overloads $ m1) m2

私は IMeasurable を持っていないのでテストしていませんが、うまくいくかもしれません。

于 2012-10-19T10:25:31.377 に答える
6

次のように動作する演算子を定義している場合+、最良の設計は、引数の型と同じ型の値を返す演算子を定義することだと思います。これは、演算子を次IMeasurableの代わりに返すように変更することを意味しintます。

type IMeasurable =
  abstract Measure : int

let newMeasure m = 
  { new IMeasurable with 
      member x.Measure = m }

let inline ( |+| ) (m1 : #IMeasurable) (m2 : #IMeasurable) = 
  newMeasure (m1.Measure + m2.Measure)

これにより、演算子の定義がより統一され、使いやすくなります。書きたかったコードが機能するようになりました ( が返されIMeasurableます) が、以下も使用できますSeq.reduce

// Now you can add multiple measure values without issues
let res = (newMeasure 2) |+| (newMeasure 3) |+| (newMeasure 4)

// Moreover, you can also use `Seq.reduce` which would not work
// with your original operator (because it has wrong type)
let res = [newMeasure 2; newMeasure 3; newMeasure 4] |> Seq.reduce (|+|)

そうは言っても、を使用して定義された演算子を本当にオーバーロードしたい場合、letそれを静的メンバーとして型に追加できない場合 (型を変更できないため)、Gustavo が説明するトリックを使用する必要があります。

于 2012-10-19T10:30:15.597 に答える