Is there an easy implementation to use a predicate function in a generic F# query

若如初见. 提交于 2019-12-12 16:07:40

问题


I want to use a generic query function like:

let filter predicateFn =
    predicateFn |>
    fun f s -> query { for x in s do 
                       where (f(x)) 
                       select x }

Where f should be a predicate function. Obviously, this cannot be translated to a sql query. But is there a solution for this problem. I have seen sample solutions for C#.

Approach taken from: Web, Cloud & Mobile Solutions with F# by Daniel Mohl.

Edit: example to clarify:

let userSorter = fun (u:users) -> u.Login

let sorted  =
    query { for user in dbConn.GetDataContext().Users do 
                sortBy ((fun (u:users) -> u.Login)(user))
                select user.Login }

Basically, I want to replace the lambda by the userSorter. As it is the above code runs, but this will fail:

let userSorter = fun (u:users) -> u.Login

let sorted  =
    query { for user in dbConn.GetDataContext().Users do 
                sortBy (userSorter(user))
                select user.Login }

回答1:


Finally found the solution, already on Stackoverflow:

open System.Linq
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns

let runQuery (q:Expr<IQueryable<'T>>) = 
  match q with
  | Application(Lambda(builder, Call(Some builder2, miRun, [Quote body])), queryObj) ->
      query.Run(Expr.Cast<Microsoft.FSharp.Linq.QuerySource<'T, IQueryable>>(body))
  | _ -> failwith "Wrong argument"

let test () =
  <@ query { for p in db.Products do
             where ((%predicate) p)
             select p.ProductName } @>
  |> runQuery
  |> Seq.iter (printfn "%s")

Credits should go to Tomas Petricek, you can have my bounty!

Edit: To match against any query result of type 'T see my other Q&A



来源:https://stackoverflow.com/questions/16800714/is-there-an-easy-implementation-to-use-a-predicate-function-in-a-generic-f-quer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!