ОНОВЛЕННЯ
Я знайшов більш просту версію за допомогою оператора ($)
замість члена. Натхненний 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
.