2014-07-19 68 views
1

我刚开始学习F#,并通过类型推断我想我会尝试从表中得到的第一条记录的功能(使用查询表达式,LINQ的风格)印象深刻:F#返回值

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

这个工程,类型是IQueryable<'a> -> 'a

但是为什么这个版本不工作?

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

不应该for n in data do head给标'a同上次一样?有人可以解释为什么第二个版本不起作用,以及如何在不使用Seq.head的情况下使其工作?

回答

1

的原因是查询生成器有正在运行的查询,具有以下重载有点哈克重载Run方法:

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> 

在你的情况下,任何一个重载的可以申请,给予适当的类型data(尽管QuerySource<_,_>是一种无法用于用户代码的类型,因此两个过载是不太可能的)。不幸的是,由于定义了这些重载的奇怪方式(第一个和第二个实际上是在单独模块中定义的扩展方法),第三个赢得了重载分辨率战。

+0

谢谢,是'result |> Seq.head'一个明智的,有效的解决方案吗? – user826840

+0

@ user826840 - 可能(尽管它可能会导致稍微不同的查询的执行),或者只是按照Nikon Third建议的那样添加类型注释。 – kvb

1

我不知道为什么,但是当你将鼠标悬停在data论点getfirst2你看到它的System.Linq.IQueryable<Linq.QuerySource<'a, System.Linq.IQueryable>>型的,当它真的应该System.Linq.IQueryable<'a>

您可通过添加类型标注“修理”它:

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

然后它就像你预料:

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

也许别人可以阐明为什么编译器推断一些轻它的类型。