简体   繁体   中英

F# returning value from query expression

I am just starting to learn F#, and impressed by the type inference I thought I would try a function that gets the first record from a table (using query expressions, Linq style):

let getfirst data = 
    let result = query { for n in data do take 1 }
    result |> Seq.head

This works, the type is IQueryable<'a> -> 'a .

But why doesn't this version work?

let getfirst2 data = 
    query { for n in data do head }

Shouldn't for n in data do head give a scalar 'a just like last time? Can someone explain why the second version doesn't work, and how to make it work without using Seq.head?

I don't know why, but when you hover over the data argument in getfirst2 you see it's of type System.Linq.IQueryable<Linq.QuerySource<'a, System.Linq.IQueryable>> when it really should be System.Linq.IQueryable<'a> .

You can "fix" it by adding type annotations:

open System.Linq
let getfirst2 (data : IQueryable<'a>) : 'a = query { 
    for item in data do
    head
}

Then it works like you have expected:

[1 .. 10]
|> System.Linq.Queryable.AsQueryable
|> getfirst2
|> printfn "%d" // Prints 1.

Maybe someone else can shed some light on why the compiler infers the types it does.

The reason is that the query builder has a somewhat hacky overloaded Run method for running queries, with the following overloads:

QueryBuilder.Run : Quotations.Expr<'t> -> 't
QueryBuilder.Run : Quotations.Expr<Linq.QuerySource<'t, IEnumerable>> -> seq<'t>
QueryBuilder.Run : Quotations.Expr<Linq.QuerySource<'t, IQueryable>> -> IQueryable<'t>

In your case, any of the overloads could apply, given a suitable type for data (though QuerySource<_,_> is a type which isn't ever meant to be used by user code, so two of the overloads are quite unlikely). Unfortunately, due to the strange way these overloads are defined (the first and second are actually extension methods defined in separate modules), the third one wins the overload resolution battle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM