用于计算F#中的排列的递归函数具有类型不匹配错误

时间:2011-12-24 08:08:28

标签: recursion f# functional-programming permutation

我正在尝试在F#中编写一个通用函数,它将返回列表的所有排列。我试图使用受java版本here

启发的递归算法来实现这一目标

但是在递归函数的最后一行,我得到了注释中给出的错误。我猜这与将递归循环退出(正在执行的 if(Array.length <= 1) then 的输出)与其余的Array.Map函数进行整理时生成的输出进行整理有关。

如果有人可以解释为什么会发生这种错误以及如何解决这个错误,我将不胜感激。

let GetPermutationsOfList inputList =

let rec innerLoop firstPart secondPart =
    if (Array.length secondPart) <= 1 then
        [| Array.append firstPart secondPart |]
    else
        let SliceAtMarkerElement m =
           let currentMarkerElement = secondPart.[m] 
           let everythingBeforeMarkerElement = secondPart.[0 .. m - 1]
           let everythingAfterMarkerElement = secondPart.[m+1 .. ]
           let newSecondPartList = Array.append everythingBeforeMarkerElement everythingAfterMarkerElement
           let newFirstPartList = Array.append firstPart [|currentMarkerElement|]
           (newFirstPartList, newSecondPartList)

        [|for i in 0 .. ((Array.length secondPart) - 1) -> i|] |> 
        Array.map(fun c -> SliceAtMarkerElement c) |>
        // The following line gives the error 
        // "Type Mismatch. Expecting a 'a but given a 'a[] The resulting type would be infinite when unifying "a' and "a[]"
        Array.map(fun d -> innerLoop (fst d) (snd d))

innerLoop Array.empty (List.toArray inputList)

1 个答案:

答案 0 :(得分:3)

假设您的函数缩进正确,错误消息非常有用。在innerLoop函数中,Array.append firstPart secondPart应返回'b []。但是,最后一行Array.map(fun d -> innerLoop (fst d) (snd d))强制它返回'b [] [],而'b []无法与innerLoop统一。

我认为您希望计算每个Array.collect中的排列,然后将这些结果连接起来。您必须使用Array.map代替[|for i in 0 .. (Array.length secondPart)-1 -> i|] |> Array.map (fun c -> SliceAtMarkerElement c) |> Array.collect (fun d -> innerLoop (fst d) (snd d))

[| for i in 0 .. (Array.length secondPart)-1 do
      let first, second = SliceAtMarkerElement i
      yield! innerLoop first second (* concatenating results *)
    |]

上面的片段使用了两个临时阵列,这很浪费。您可以仅使用计算表达式来消除这些额外的数组:

map

<强>更新

正如注释中所阐明的那样,您希望返回一个数组数组,其中每个数组都是一个排列。因此,您的更改将起作用,[| for i in 0 .. (Array.length secondPart)-1 do let first, second = SliceAtMarkerElement i yield innerLoop first second (* returning each array as a permutation *) |] 操作应该是:

{{1}}