F#でnestednessの任意のレベルのリストを合計します

runeks:

私は、リストの合計を返します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#でこれを達成することができますか?

AMieres:

更新

私は、オペレータ使って簡単なバージョンを見つけた($)代わりのメンバーを。触発さ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 ている戻りますintSRTPsを使用する場合の一般的な機能はする必要がありますinline

それは難しい部分ではありません。難しいのは、「追加」されるSumように既存の型にメンバーをintし、List許可されていません。しかし、我々は新しいタイプに追加することができますSumOperationsし、制約に含める常にあることを行っています(^t or ^a)^tSumOperations

  • 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

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=30301&siteId=1