2012-04-30 2 views
3

J'essaie de définir le type de requêtes de la nomenclature en utilisant la syntaxe de compréhension de requête F # 3.0 récemment introduite. Bien qu'il soit possible de définir ce type de requêtes en utilisant des compréhensions de yield! pour des collections en mémoire, je n'ai pas manqué de les traduire en requêtes de requêtes qui ciblent des sources IQueryable distantes. Je suppose que la partie la plus difficile serait de «former» le fournisseur à reconnaître les expressions de table communes à partir de modèles récursifs.Compréhensions de requêtes récursives (F # 3.0)

Des idées?

+0

Je ne veux pas être méchant, mais si vous avez l'intention de poster ici encore, vous pouvez regarder ceci: http://stackoverflow.com/faq#signatures Vous n'avez pas besoin d'une signature ou d'un slogan et en fait c'est un peu découragé. –

Répondre

5

Malheureusement, je ne pense pas que la prise en charge de la syntaxe de requête actuelle dans F # 3.0 est capable de gérer les requêtes récursives. Le problème principal est que F # 3.0 repose sur les implémentations IQueryable standard qui ont été conçues principalement pour C# et donc ils ne s'attendent pas à des structures récursives. Je pense que soutenir cela serait assez difficile. Vous pouvez implémenter vos propres citations F # dans le traducteur SQL (ce qui est difficile) ou implémenter une sorte de pré-processeur qui prend une citation F # (requête) qui contient la récursivité et traduit la récursion en quelque chose que le traducteur LINQ to SQL peut traiter avec (mais c'est probablement difficile aussi).

En général, l'approche serait de définir votre propre générateur de requêtes:

open System.IO 
open Microsoft.FSharp.Quotations 

type MyQueryBuilder() = 
    member x.For(a, body) = Seq.collect body a 
    member x.Quote(e) = e 
    member x.YieldFrom(s) = s 
    member x.Run(e:Expr<'T>) : 'T = failwithf "%A" e 

// Example using the custom query builder 
// (fails, printing the quoted query) 
let mquery = MyQueryBuilder()  
let n = [1 .. 10] 

let rec nums a : seq<int> = 
    mquery { for b in n do 
      yield! nums b } 

Dans la méthode Run, vous obtenez une citation qui représente la requête. Vous pouvez pré-traiter cela et remplacer tous les appels à MyQueryBuilder par des appels aux opérations query standard et remplacer la récursivité par autre chose. Ensuite, vous pouvez appeler query.Run (pour exécuter l'implémentation standard IQueryable). Cependant, comme je l'ai dit, cela va probablement être assez difficile à mettre en œuvre - mais peut-être, si vous avez un type spécifique de récursion que vous pouvez facilement gérer, cela pourrait être une option. Cependant, si LINQ to SQL ne génère pas d'expressions de table communes pour des motifs standard, je ne pense pas que vous puissiez l'entraîner pour les générer. Pour autant que je sache, le traducteur n'est pas vraiment extensible.