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 Sum
batasan 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" Sum
anggota ke tipe seperti yang ada int
dan List
yang tidak diizinkan. Tapi, kita bisa menambahkannya ke tipe baru SumOperations
dan memasukkan dalam batasan di (^t or ^a)
mana ^t
akan selalu ada SumOperations
.
getSum0
mendeklarasikan Sum
batasan anggota dan memintanya.
getSum
lolos SumOperations
sebagai parameter tipe pertama kegetSum0
Baris static member inline Sum(x : float ) = int x
ditambahkan 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)))) nestedList
mana jumlahdictList
cocok dengan jumlah[]
dalam tipenestedList
.