MEMPERBARUI
Saya menemukan versi yang lebih sederhana menggunakan operator dan ($)bukan anggota. Terinspirasi oleh 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
Penjelasan lainnya masih berlaku dan ini berguna ...
Saya menemukan cara untuk memungkinkannya:
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
Menjalankan contoh Anda:
let list v = List.replicate 6 v
1
|> list |> list |> list |> list |> list
|> list |> list |> list |> list |> list
|> getSum |> printfn "%d" // = 60466176
Ini didasarkan pada penggunaan SRTP dengan batasan anggota:, static member Sumbatasan tersebut mengharuskan jenis untuk memiliki anggota yang dipanggil Sum
yang mengembalikan sebuah int. Saat menggunakan SRTP, fungsi generik harus inline.
Itu bukan bagian yang sulit. Bagian yang sulit adalah "menambahkan" Sumanggota ke tipe seperti yang ada intdan Listyang tidak diizinkan. Tapi, kita bisa menambahkannya ke tipe baru SumOperationsdan memasukkan dalam batasan di (^t or ^a)
mana ^takan selalu ada SumOperations.
getSum0mendeklarasikan Sumbatasan anggota dan memintanya.
getSum lolos SumOperationssebagai parameter tipe pertama kegetSum0
Baris static member inline Sum(x : float ) = int xditambahkan untuk meyakinkan kompiler untuk menggunakan panggilan fungsi dinamis generik dan bukan hanya default static member inline Sum(x : int )ketika meneleponList.sumBy
Seperti yang Anda lihat sedikit berbelit-belit, sintaksisnya kompleks dan perlu untuk mengatasi beberapa keanehan pada kompiler tetapi pada akhirnya itu mungkin.
Metode ini dapat diperluas untuk bekerja dengan Array, tuple, opsi, dll. Atau kombinasi dari semuanya dengan menambahkan lebih banyak definisi ke 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)))) nestedListmana jumlahdictListcocok dengan jumlah[]dalam tipenestedList.