7

I am trying use the Lex.Db database in an F# project in a WinRT 8.1 app.

I am following this tutorial for C#. I've successfuly added a reference to Lex.Db to an F# project and the simple calls in the tutorial translate to f# and compile (eg. let db = new DbInstance("demo")).

The problem is this C# code:

db.Map<Contact>().Key(i => i.Id)

-- Edit --

To save others from reading further, in F# 3.0 this is almost a non-problem. See kvb's comment below. The solution is:

db.Map<Contact>().Key(fun i => i.Id)

-- /Edit ---

The Key function expects an Expression<Func<Contact,'a>> and I am unable to build this in F#.

A very similar question appears in How to pass LinQ Expressions from F# to C# code. The recommended solution is to use LeafExpressionConverter.QuotationToLambdaExpression.

I have tried this as follows:

 type Contact() =
    member val Id = 0 with get, set
    member val FirstName = "" with get, set

 let db = new DbInstance("Demo")

 let idExpr = LeafExpressionConverter.QuotationToLambdaExpression
                        <@ fun (c : Contact) -> c.Id @>

 db.Map<Contact>().Key(idExpr) |> ignore    // <- Error

This produces a compiler error on idExpr:

Type mismatch. Expecting a Expression<Func<Contact,'a>> but given a Expression<(Contact -> int)>. The type 'Func<Contact,'a>' does not match the type 'Contact -> int'.

This question: Expression<Func<T, bool>> from a F# func seems to address the problem directly, but the solution uses Microsoft.FSharp.Linq.QuotationEvaluation, which I can't find in F# 3.0 for WinRT.

How do I turn <@ fun (c : Contact) -> c.Id @> into an Expression<Func<Contact,'a>>?

Community
  • 1
  • 1
Stephen Hosking
  • 1,405
  • 16
  • 34
  • 2
    What happens if you just try `db.Map.Key(fun i -> i.Id)` in F#? F# 3.0 should apply a type-directed conversion when you pass a lambda where an `Expression` is expected. – kvb Apr 30 '14 at 17:11
  • That works #kvb, without any more ceremony! It compiles and runs. I've now got an F# View Model bound to a C# WinRT View, and the View Model reads from the database with just these few lines of code (almost..there are just a few more lines which are obvious from the tutorial and for exposing the View Model to data binding). Thankyou! – Stephen Hosking Apr 30 '14 at 23:07

1 Answers1

11

Microsoft.FSharp.Linq.QuotationEvaluation is in PowerPack, but as of v3.0 the functionality it provides is available in Core via LeafExpressionConverter. You can use the code in the question you linked, but change it to use LeafExpressionConverter for the translation part.

open System
open System.Linq.Expressions
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.RuntimeHelpers

let toLinq (expr : Expr<'a -> 'b>) =
  let linq = LeafExpressionConverter.QuotationToExpression expr
  let call = linq :?> MethodCallExpression
  let lambda = call.Arguments.[0] :?> LambdaExpression
  Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters) 
Daniel
  • 47,404
  • 11
  • 101
  • 179
  • Thankyou! This is correct and works. I can use it in my code as follows: `.Key(<@ fun (c : Contact) -> c.Id @> |> toLinq)`. – Stephen Hosking Apr 30 '14 at 23:16
  • Readers, please note that @kvb's comment in my OP provides a simpler solution which works for my case. Daniel's solution will be helpful for building an expression with these various lower level API's, in F# 3.0. – Stephen Hosking Apr 30 '14 at 23:23