2

デカルト生成には、十分な関数があります-そのように定義されたシーケンス:

let rec sequence = function 
  | []      -> Seq.singleton [] 
  | (l::ls) -> seq { for x in l do for xs in sequence ls do yield (x::xs) } 

しかし、その結果を見てください:

シーケンス [[1..2];[1..10000]] |> Seq.skip 1000 ;; val it : seq = seq [[1; 1001]; [1; 1002]; [1; 1003]; [1; 1004]; ...]

ご覧のとおり、製品の最初の「座標」は非常にゆっくりと変化し、2 番目のリストが終了すると値が変化します。

私は次のように自分のシーケンスを書きました(以下のコメント):

/// Sum of all producted indeces = n
let rec hyper'plane'indices indexsum maxlengths =
    match maxlengths with 
    | [x]        -> if indexsum < x then [[indexsum]] else []
    | (i::is)   -> [for x in [0 .. min indexsum (i-1)] do for xs in hyper'plane'indices (indexsum-x) is do yield (x::xs)]
    | []        -> [[]]

let finite'sequence = function
    | [] -> Seq.singleton []
    | ns -> 
        let ars = [ for n in ns -> Seq.toArray n ]
        let length'list = List.map Array.length ars
        let nmax = List.max length'list
        seq { 
            for n in [0 .. nmax] do 
            for ixs in hyper'plane'indices n length'list do 
                yield (List.map2 (fun (a:'a[]) i -> a.[i]) ars ixs) 
        } 

重要なアイデアは、(2 つの) リストを (2 つの) 直交する次元として見ることです。すべての要素は、リスト内のインデックスによってマークされます。したがって、デカルト積のすべてのセクションのすべての要素を超平面 (2D の場合は線) で列挙することにより、すべての要素を列挙できます。言い換えれば、最初の列に [1;1] から [1;10000] までの値が含まれ、2 番目の列に [2;1] から [2;10000] までの値が含まれている Excel のシートを想像してください。そして、番号1の「超平面」はセルA2とセルB1を結ぶ線です。私たちの例では

hyper'plane' インデックス 0 [2;10000];; val it : int list list = [[0; 0]]
超'平面' インデックス 1 [2;10000];; val it : int list list = [[0; 1]; [1; 0]]
超'平面' インデックス 2 [2;10000];; val it : int list list = [[0; 2]; [1; 1]]超「平面」
インデックス 3 [2;10000];; val it : int list list = [[0; 3]; [1; 2]]超「平面」
インデックス 4 [2;10000];; val it : int list list = [[0; 4]; [1; 3]]

与えられたリストから生成しているインデックスと配列がある場合、シーケンスを {プレーン 0 のすべての要素; 平面 1 のすべての要素より ... など } であり、元のシーケンスよりも揮発性の高い関数を取得します。

しかし、finite'sequenceは非常に貪欲な関数であることが判明しました。そして今、質問です。どうすれば改善できますか?

ご多幸をお祈り申し上げます、アレキサンダー。(そして下手な英語でごめんなさい)

4

1 に答える 1