How do you compose query expressions in F#?

前端 未结 2 1745
梦毁少年i
梦毁少年i 2020-12-12 18:48

I\'ve been looking at query expressions here http://msdn.microsoft.com/en-us/library/vstudio/hh225374.aspx

And I\'ve been wondering why the following is legitimate

2条回答
  •  温柔的废话
    2020-12-12 19:05

    Naively, in the original example one could try to quote the predicate, and then splice it in:

    let christmasPredicate = <@ fun (x:Catalog.ServiceTypes.Title) -> 
                                 x.Name.Contains("Christmas") @>
    let testQuery = query {
            for number in netflix.Titles do
            where ((%christmasPredicate) number) 
            select number
        }
    

    (I've taken the liberty of cleaning up the original example slightly)

    Examples such as this (with simple, first-order lambda-abstractions) often do work in F# anyway, but in general, there is no guarantee that F#'s default QueryBuilder will normalize away the resulting applications of lambda-abstractions in the quoted term. This can result in strange error messages, or in queries with poor performance (e.g. querying one table and then generating one query on another table per row of the first table, instead of doing a single query join).

    We recently developed a library called FSharpComposableQuery that (if opened) overloads the query operator to perform normalization (and to do some other helpful things). It provides a strong guarantee to generate a single query for a nontrivial subset of F# query expressions. Using FSharpComposableQuery's version of query, the above naive composition works. We have also tested extensively to try to ensure that FSharpComposableQuery doesn't break existing query code.

    Similarly, for example, using FSharpComposableQuery, Tomas's example does not require the special RunQuery function. Instead, one can simply do:

    open FSharpComposableQuery
    
    let predicate = <@ fun (p:Nwind.ServiceTypes.Product) -> 
                         p.UnitPrice.Value > 50.0M @>
    let test () =
      query { for p in db.Products do
              where ((%predicate) p)
              select p.ProductName }
      |> Seq.iter (printfn "%s")
    

    (Caveat: I have only tested the above code only with the OData version of Northwind, not the SQL type provider, but we have tested a large number of similar and more complex examples. The OData version fails with a mysterious error from OData, but this seems orthogonal to the matter at hand.)

    FSharpComposableQuery is now available from NuGet here: https://www.nuget.org/packages/FSharpComposableQuery

    and more information (including examples and a small tutorial, demonstrating more complex forms of composition) can be found here:

    http://fsprojects.github.io/FSharp.Linq.ComposableQuery/

    [EDIT: Changed the above links to remove the word "Experimental", since the project name has changed.]

提交回复
热议问题