私は、リストの合計を返しますF#関数を作成しようとしているint
任意のnestednessの秒。すなわち。それがために働くだろうlist<int>
、list<list<int>>
とlist<list<list<list<list<list<int>>>>>>
。
Haskellでは、私は次のように記述します。
class HasSum a where
getSum :: a -> Integer
instance HasSum Integer where
getSum = id
instance HasSum a => HasSum [a] where
getSum = sum . map getSum
これは私にやらせるだろう。
list :: a -> [a]
list = replicate 6
nestedList :: [[[[[[[[[[Integer]]]]]]]]]]
nestedList =
list $ list $ list $ list $ list $
list $ list $ list $ list $ list (1 :: Integer)
sumNestedList :: Integer
sumNestedList = getSum nestedList
どのように私はF#でこれを達成することができますか?
更新
私は、オペレータ使って簡単なバージョンを見つけた($)
代わりのメンバーを。触発さ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
これは、メンバーの制約でSRTPsを使用してに基づいていますstatic member Sum
、制約と呼ばれるメンバー持っているタイプを必要としSum
ている戻りますint
。SRTPsを使用する場合の一般的な機能はする必要があります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