我正在尝试在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)
答案 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}}