1

我有以下代码块:

let rec Sieve p nums =
    let filtered = query { for n in nums do 
                            where (n % p = 0 && n <> p)
                            select n } |> Seq.toList
    if filtered = nums then filtered       // Error
    else
        let nextIndex = 1 + (filtered |> List.findIndex (fun x -> x = p))
        if nextIndex > filtered.Length then filtered
        else
            let next = filtered.[nextIndex]
            Sieve next filtered 

当我编译这个时,我得到'类型''a list'与'System.Linq.IQueryable<'a>'不兼容。在我用注释错误标记的行上。

我发现如果我为 Sieve 添加类型注释以使其成为 nums (nums: int list),那么它将正常工作。但是,如果我替换 nums 就行了

if filtered = nums then filtered

和:

if filtered = [1..10] then filtered

然后我得到相同的错误,指的是在线过滤:

Sieve next filtered

因为当我被过滤时,我在使用它之前将其直接转换为列表,为什么会出现此错误?

4

1 回答 1

3

我会说这是类型检查器的令人困惑的行为。

如果nums事先不知道 type of (如您的示例中所示),则类型检查器会查看第一次使用 of numsinquery块并将其推断为IQueryable<'a>. 由于 F# List 没有实现接口,因此之间的IQueryable统一失败了。'a listIQueryable<'a>

如果你在声明中指定了numsas的类型,那么in的使用看起来就像是对集合的正常使用。'a listnumsfor n in nums doIEnumerable

那就是说你使用了错误的工具来完成这项工作。查询表达式旨在用于处理外部数据源。应该通过序列表达式来促进内存中的查询:

let filtered = seq { for n in nums do 
                        if n % p = 0 && n <> p then
                             yield n } |> Seq.toList
于 2012-07-29T15:28:43.893 回答