F#:如何找到笛卡尔幂

F#:如何找到笛卡尔幂,f#,functional-programming,F#,Functional Programming,我写笛卡尔幂函数有问题。我找到了许多关于计算笛卡尔积的例子,但没有一个是关于笛卡尔幂的。 例如,[1;2]被提升到3=[[1;1;1];[1;1;2];[1;2;1];[1;2;2];[2;1;2];[2;2;2;1];[2;2;2] 我使用以下代码计算笛卡尔积: let Cprod U V = let mutable res = [] for u in U do for v in V do res <

我写笛卡尔幂函数有问题。我找到了许多关于计算笛卡尔积的例子,但没有一个是关于笛卡尔幂的。
例如,[1;2]被提升到3=[[1;1;1];[1;1;2];[1;2;1];[1;2;2];[2;1;2];[2;2;2;1];[2;2;2]
我使用以下代码计算笛卡尔积:

 let Cprod U V =
        let mutable res = []
        for u in U do
            for v in V do
                res <- res @ [[u;v]]
        res
let Cpower U n =
    let mutable V = U
    for i=0 to n-1 do
        V <- Dprod U V
    V
让Cprod U V=
设可变res=[]
为你做的事
对于v-in-v-do
res我解决了我的问题:

let rec Cprod = function
    | [] -> [[]]
    | hs::tss ->
        [ for h in hs do            
            for ts in D tss ->
                h::ts]

let Cpower U n = 
    let mutable inp = []
    for i=0 to n-1 do
        inp <- inp @ [U]
    Dprod inp
让rec Cprod=函数
| [] -> [[]]
|hs::tss->
[适用于hs-do中的h
对于D tss中的ts->
h::ts]
设Cpower U n=
设可变inp=[]
对于i=0到n-1 do

inp至于错误的来源,我们有以下类型的限制

// Cprod: seq<`a> -> seq<`a> -> `a list list
let Cprod U V =
    ...

// Cpower: seq<`a> -> int -> ???
let Cpower U n =
    // V: seq<`a>
    let mutable V = U
    // n: int
    for i=0 to n-1 do
        (* The next line implies two type constraints:
           V: seq<`a>
           V: `a list list *)
        V <- Dprod U V
    V
//Cprod:seq->seq->`列表
让我们一起来=
...
//Cpower:seq->int->???
让我们共同努力=
//五:seq
设可变V=U
//n:int
对于i=0到n-1 do
(*下一行表示两种类型约束:
五:seq
V:`列表*)

V以下是从Haskell移植的一个版本:

let replicate n x = [for i in 1 .. n -> x]
let sequence ms = 
  List.fold (fun m' m -> [for x in m do for xs in m' -> (x::xs)]) [[]] ms
let Cpower n l = replicate n l |> sequence
它的工作原理类似于计数:如果您将
l
视为数字,那么它会复制它们以获得您拥有的位数,然后使用
序列对它们进行计数

换句话说,所有小于2^3的二进制数都可以通过将
[0;1]
复制3次来生成
[[0;1];[0;1];[0;1]
,然后对其运行
序列

通过切换到
顺序折叠
,可以使这一点变得更慢:

let sequence' ms =
  Seq.fold (fun m' m -> seq {for x in m do for xs in m' do yield (x::xs)})
           (seq {yield []})
           ms
let rec cartesianPow input n = seq {
  if (n = 1) then
    // This handles the case when the recursion terminates. We need to turn
    // each element from the input into a list containing single element:
    //   [1; 2; 4] ^ 1 = [ [1]; [2]; [3] ]
    for el in input do 
      yield [el]
  else
    // We perform one Cartesian product (and run the rest of the 
    // power calculation recursively). Mathematically:
    //   [1; 2; 3] ^ n = [1; 2; 3] x ([1; 2; 3] ^ (n-1))
    for el in input do 
      for rest in cartesianPow input (n - 1) do
        yield el :: rest }

cartesianPow [ 0; 1 ] 3

这将为您提供一系列结果,而不是列表。不幸的是,我无法通过查看它来判断它是否足够懒:它可能必须在内存中生成整个列表才能开始为您提供第一个元素。您应该能够通过在调试器中单步执行它来找到答案。(或者你可能比我更擅长阅读懒惰。)

我还想补充一点,在编写F#代码时,通常更倾向于避免使用
可变的
值。当您学习F#或需要优化某些代码以加快运行时,这很好,但如果您想编写更惯用的F#代码,最好使用递归,而不是
可变的

我试图更优雅地书写笛卡尔的力量,这是我的版本。它是递归实现的。当我们需要计算
X^1
时,我显式地处理这种情况,递归情况执行如下笛卡尔积:
X^n=X*X^(n-1)

我使用的是序列表达式,该方法使用
yield
生成序列元素(作为结果返回):

let sequence' ms =
  Seq.fold (fun m' m -> seq {for x in m do for xs in m' do yield (x::xs)})
           (seq {yield []})
           ms
let rec cartesianPow input n = seq {
  if (n = 1) then
    // This handles the case when the recursion terminates. We need to turn
    // each element from the input into a list containing single element:
    //   [1; 2; 4] ^ 1 = [ [1]; [2]; [3] ]
    for el in input do 
      yield [el]
  else
    // We perform one Cartesian product (and run the rest of the 
    // power calculation recursively). Mathematically:
    //   [1; 2; 3] ^ n = [1; 2; 3] x ([1; 2; 3] ^ (n-1))
    for el in input do 
      for rest in cartesianPow input (n - 1) do
        yield el :: rest }

cartesianPow [ 0; 1 ] 3

这不是最有效的实现(例如,因为在
for
循环中使用
yield
可能不是一件好事),但这是大型
n
的唯一问题。在F#中,通常最好从更容易理解的最干净的实现开始:-)。

您知道@has linear runtime是吗?最后使用::和反转(如果有必要的话)将比使用@快得多。