F#:如何找到笛卡尔的力量

时间:2010-04-15 19:54:50

标签: f# functional-programming

我在编写笛卡尔幂函数时遇到问题。我发现了许多关于计算笛卡尔积的例子,但没有关于笛卡尔幂的例子 例如,[1; 2]上升到幂3 = [[1; 1; 1]; [1; 1; 2]; [1; 2; 1]; [1; 2; 2]; [2; 1; 1]; [2; 1; 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

Visual Studio说:错误在统一''a'和''列表'时,结果类型将是无限的。我会感谢任何帮助和链接。

4 个答案:

答案 0 :(得分:2)

至于错误的来源,我们有以下类型约束

// 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

V必须是seq<`a>`a list list,并且U和V必须具有相同的类型才意味着`a = `a list,这就是“无限类型“错误消息(无限类型为... list list list list。即使V的值是可变的,它也必须是单一类型。

答案 1 :(得分:1)

这是从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视为数字,则会根据您拥有的地点数复制它们,然后使用sequence计算它们。

换句话说,所有二进制数小于2 ^ 3都可以通过复制[0;1] 3次来生成[[0;1]; [0;1]; [0;1]]然后再运行sequence来生成。

切换到Seq.fold

可以使这更加懒散
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

这为您提供了结果的seq而不是列表。不幸的是,我不能通过查看它是否懒得足够:它可能必须在内存中生成整个列表以开始为您提供第一个元素。您应该能够通过在调试器中单步调试来找到它。 (或者你可能比我更善于阅读懒惰。)

答案 2 :(得分:1)

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

我试着更优雅地写出笛卡尔的力量,这是我的版本。它是递归实现的。当我们需要计算X^1并且递归案例执行像这样的笛卡尔积时,我明确地处理了这个案例:X^n = X * X^(n-1)

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

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

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

答案 3 :(得分:0)

我解决了我的问题:

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