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 

これをコンパイルすると、次のようになります。タイプ''リスト'は'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事前にわからない場合(例のように)、タイプチェッカーはnumsinqueryブロックの最初の使用を調べ、それをとして推測しIQueryable<'a>ます。F#リストはインターフェイスを実装していないため、と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 に答える