GÜNCELLEME
Üye ($)
yerine operatör kullanarak daha basit bir sürüm buldum . Https://stackoverflow.com/a/7224269/4550898 adresinden ilham alındı :
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
Açıklamanın geri kalanı hala geçerlidir ve yararlıdır ...
Bunu mümkün kılmak için bir yol buldum:
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
Örneğinizi çalıştırma:
let list v = List.replicate 6 v
1
|> list |> list |> list |> list |> list
|> list |> list |> list |> list |> list
|> getSum |> printfn "%d" // = 60466176
Bu, üye kısıtlamaları olan SRTP'lerin kullanılmasına dayanır: static member Sum
kısıtlama, türün bir Sum
döndüren bir üyeye sahip olmasını gerektirir int
. SRTP'leri kullanırken genel işlevlerin olması gerekir inline
.
Zor kısmı bu değil. Zor kısım, Sum
üye olan int
ve List
buna izin verilmeyen mevcut bir türe "ekleme" dir . Ama biz yeni bir türüne ekleyebilirsiniz SumOperations
ve kısıtlama dahil hep olacak .(^t or ^a)
^t
SumOperations
getSum0
Sum
üye kısıtlamasını bildirir ve çağırır.
getSum
SumOperations
ilk tip parametresi olarak geçergetSum0
Hat static member inline Sum(x : float ) = int x
, derleyiciyi yalnızca static member inline Sum(x : int )
arama sırasında varsayılan olarak değil, genel bir dinamik işlev çağrısı kullanmaya ikna etmek için eklendiList.sumBy
Gördüğünüz gibi biraz kıvrımlı, sözdizimi karmaşık ve derleyici üzerinde bazı tuhaflıklar etrafında çalışmak gerekiyordu ama sonunda mümkün oldu.
Bu yöntem Diziler, tuples, seçenekler vb. Veya bunların herhangi bir kombinasyonu ile çalışmak için genişletilebilir 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
sayısının olduğu gibi bir şey olacaktır .dictList
[]
nestedList