Skip to content

Instantly share code, notes, and snippets.

@habib-sadullaev
Last active August 19, 2020 08:23
Show Gist options
  • Save habib-sadullaev/a2cf8be7af390d41657130bdfa286f5d to your computer and use it in GitHub Desktop.
Save habib-sadullaev/a2cf8be7af390d41657130bdfa286f5d to your computer and use it in GitHub Desktop.
strongly type expression splices
open FSharp.Quotations
open FSharp.Linq.RuntimeHelpers
open System.Linq
open System
type AST =
| StartsWith of string
| Contains of string
| EndsWith of string
| And of AST * AST
| Or of AST * AST
let (<||>) l r = Or(l, r)
let (<&&>) l r = And(l, r)
let convert ast =
let param = Var("x", typeof<string>)
let var = Expr.Var param |> Expr.Cast<string>
let rec visit expr =
match expr with
| StartsWith x ->
<@ (%var).StartsWith x @>
| Contains x ->
<@ (%var).Contains x @>
| EndsWith x ->
<@ (%var).EndsWith x @>
| And (a, b) ->
let left = visit a
let right = visit b
<@ %left && %right @>
| Or (a, b) ->
let left = visit a
let right = visit b
<@ %left || %right @>
Expr.Lambda(param, visit ast)
|> Expr.Cast<string -> bool>
let toLambdaExpression ast =
match convert ast with
| ExprShape.ShapeLambda(var, body) ->
Expr.NewDelegate(typeof<Func<string, bool>>, [var], body)
|> Expr.Cast<Func<string, bool>>
|> LeafExpressionConverter.QuotationToLambdaExpression
| _ -> failwithf "must be lambda"
let predicate =
Contains "abc" <||> (StartsWith "a" <&&> EndsWith "B")
|> toLambdaExpression
[ "aaaaBBBB"; "xxxabcxxx"; "xxx" ]
.AsQueryable()
.Where(predicate)
.ToList()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment