CẬP NHẬT
Tôi tìm thấy một phiên bản đơn giản hơn bằng cách sử dụng một toán tử ($)
thay vì một thành viên. Lấy cảm hứng từ 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
Phần còn lại của lời giải thích vẫn được áp dụng và nó rất hữu ích ...
Tôi tìm thấy một cách để làm cho nó có thể:
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
Chạy ví dụ của bạn:
let list v = List.replicate 6 v
1
|> list |> list |> list |> list |> list
|> list |> list |> list |> list |> list
|> getSum |> printfn "%d" // = 60466176
Điều này dựa trên việc sử dụng SRTP với các ràng buộc thành viên : static member Sum
, ràng buộc này yêu cầu loại phải có một thành viên được gọi Sum
trả về một int
. Khi sử dụng các chức năng chung SRTP cần phải có inline
.
Đó không phải là phần khó khăn. Phần khó là "thêm" Sum
thành viên vào loại hiện có int
và List
không được phép. Nhưng, chúng ta có thể thêm nó vào một loại mới SumOperations
và đưa vào chế (^t or ^a)
nơi ^t
sẽ luôn luôn được SumOperations
.
getSum0
tuyên bố các Sum
ràng buộc thành viên và gọi nó.
getSum
chuyển SumOperations
làm tham số loại đầu tiên chogetSum0
Dòng static member inline Sum(x : float ) = int x
được thêm vào để thuyết phục trình biên dịch sử dụng lệnh gọi hàm động chung và không chỉ mặc định static member inline Sum(x : int )
khi gọiList.sumBy
Như bạn có thể thấy là một chút phức tạp, cú pháp rất phức tạp và cần phải làm việc xung quanh một số quirks trên trình biên dịch nhưng cuối cùng thì điều đó là có thể.
Phương pháp này có thể được mở rộng để làm việc với Mảng, bộ dữ liệu, tùy chọn, v.v. hoặc bất kỳ sự kết hợp nào của chúng bằng cách thêm nhiều định nghĩa vào 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
số lượngdictList
khớp với số lượng[]
trong loạinestedList
.