更新
($)
メンバーの代わりに演算子を使用した単純なバージョンを見つけました。https://stackoverflow.com/a/7224269/4550898に触発されました:
type SumOperations = SumOperations
let inline getSum b = SumOperations $ b // <-- puting this here avoids defaulting to int
type SumOperations with
static member inline ($) (SumOperations, x : int ) = x
static member inline ($) (SumOperations, xl : _ list) = xl |> List.sumBy getSum
説明の残りの部分は引き続き適用され、便利です...
私はそれを可能にする方法を見つけました:
let inline getSum0< ^t, ^a when (^t or ^a) : (static member Sum : ^a -> int)> a : int =
((^t or ^a) : (static member Sum : ^a -> int) a)
type SumOperations =
static member inline Sum( x : float ) = int x
static member inline Sum( x : int ) = x
static member inline Sum(lx : _ list) = lx |> List.sumBy getSum0<SumOperations, _>
let inline getSum x = getSum0<SumOperations, _> x
2 |> getSum |> printfn "%d" // = 2
[ 2 ; 1 ] |> getSum |> printfn "%d" // = 3
[[2; 3] ; [4; 5] ] |> getSum |> printfn "%d" // = 14
あなたの例を実行する:
let list v = List.replicate 6 v
1
|> list |> list |> list |> list |> list
|> list |> list |> list |> list |> list
|> getSum |> printfn "%d" // = 60466176
これは、メンバー制約でSRTPを使用することに基づいています。static member Sum
制約では、型には、Sum
を返すメンバーが呼び出される必要がありint
ます。SRTPを使用する場合、汎用関数はである必要がありますinline
。
それは難しい部分ではありません。難しい部分はSum
、既存のタイプにメンバーを「追加」することでint
あり、List
これは許可されていません。しかし、それを新しいタイプに追加して、常に
がどこSumOperations
にあるかを制約(^t or ^a)
に含める^t
ことができますSumOperations
。
getSum0
Sum
メンバー制約を宣言して呼び出します。
getSum
SumOperations
最初のタイプパラメータとして 渡すgetSum0
ラインはstatic member inline Sum(x : float ) = int x
、一般的なダイナミックな関数呼び出しを使用するようにコンパイラを説得するために追加さだけにデフォルト設定されていませんstatic member inline Sum(x : int )
呼び出すときList.sumBy
ご覧のように少し複雑ですが、構文は複雑であり、コンパイラのいくつかの癖を回避する必要がありましたが、最終的には可能でした。
このメソッドは、配列、タプル、オプションなど、またはそれらに任意の組み合わせを使用するように拡張して、さらに定義を追加することができますSumOperations
。
type SumOperations with
static member inline ($) (SumOperations, lx : _ [] ) = lx |> Array.sumBy getSum
static member inline ($) (SumOperations, a : ^a * ^b ) = match a with a, b -> getSum a + getSum b
static member inline ($) (SumOperations, ox : _ option) = ox |> Option.map getSum |> Option.defaultValue 0
(Some 3, [| 2 ; 1 |]) |> getSum |> printfn "%d" // = 6
https://dotnetfiddle.net/03rVWT
getSum (dictList (dictList (..... (dictList dictInt)))) nestedList
の数とdictList
一致するようなもの[]
ですnestedList
。