F# - 结果类型将是无限错误

时间:2016-11-02 14:05:10

标签: f#

以下是根据此处的实现生成所有排列的简单代码:All permutations of a list

let concatElement element sequence =
    seq {
        yield element
        yield! sequence
    }

let rec permute (choices : 'a seq)=
    seq {
        if Seq.isEmpty choices then
            yield Seq.empty
        else
            for choice in choices do
                let remaining = choices |> Seq.where (fun el -> el <> choice)
                yield concatElement choice (permute remaining)
    }

我收到编译时错误“在"yield concatElement choice (permute remaining)"

上统一''a'和'seq&lt;'a&gt;'”时,结果类型将是无限的

这里有什么问题?

2 个答案:

答案 0 :(得分:4)

您尝试yield 'a seq作为类型为'a seq的序列的单个元素。要使其工作,那么'a必须与'a seq的类型相同,依此类推,因此类型为“无限” - 您必须无限地嵌套它们才能“工作”

我在你的回答中看到你认识到你必须以某种方式遍历序列元素。您可以使用for .. in语法进行迭代,或者F#为您提供实际执行此操作的yield!运算符。本着这种精神,你的回答可以写成

let rec permute (choices : 'a seq) (permBuilder: 'a seq) : seq<seq<'a>>= seq {
    if Seq.isEmpty choices then
        yield permBuilder
    else
        for choice in choices do
            let remaining = choices |> Seq.where (fun el -> el <> choice)
            let newBuilder = concatElement choice permBuilder 
            yield! permute remaining newBuilder }

或者,或者,我们可以使用Seq.collect函数为我们自动收集一系列序列(序列!),我们留下了很好的函数式代码,没有显式的迭代器:

let prepend element sequence = seq { yield element; yield! sequence }

let rec permute input =
    if Seq.length input <= 1 then Seq.singleton input
    else
        let without element = Seq.where ((<>) element) input
        let permutations element = permute (without element) |> Seq.map (prepend element)
        Seq.collect permutations input

要考虑的事情:如果你有两个不同的元素会发生什么?例如,如果您尝试获取[1; 1; 2]的排列,会发生什么?你当前的方法无法妥善处理 - 即使你改进了without关闭,你也会得到重复的答案。

答案 1 :(得分:1)

我想我明白了

let concatElement element sequence =
    seq {
        yield element
        yield! sequence
    }

let rec permute (choices : 'a seq) (permBuilder: 'a seq) : seq<seq<'a>>=
    seq {
        if Seq.isEmpty choices then
            yield permBuilder
        else
            for choice in choices do
                let remaining = choices |> Seq.where (fun el -> el <> choice)
                let newBuilder = concatElement choice permBuilder 
                for perm in permute remaining newBuilder do
                    yield perm

正如李已经评论过的那样,我试图连续seq&lt;'a&gt;用seq&lt; SEQ&LT;'一&GT;取代。我的代码缺少排列循环。