2015-10-19 43 views
4

我學習F#現在正在閱讀有關計算表達式和查詢表達式與SQL類型的提供者使用。我在做一些簡單的任務,並在來連接(聯盟)的2個查詢,我的第一個念頭,讀取序列,並列出有關yield後需要一些點是做同樣的查詢表達式像這裏面:F#查詢表達式產生

query { 
    yield! for a in db.As select { // projection } 
    yield! for b in db.Bs select { // projection } 
} 

這是無效的代碼,然後我的第二個方法是「CONCAT」他們使用:

seq { 
    yield! query {...} 
    yield! query {...} 
} 

或用LINQ的Concat功能是這樣的:(query {...}).Concat(query {...})。如何做到這一點從這question的回答

上述兩種方法的工作有一點區別,但使用seq將運行2 SQL查詢,並且Concat只運行一個是可以理解的。

我的問題則是:爲什麼不yield支持查詢表達式?


編輯:

在進一步調查之後我到了MSDN docs,我看到了YieldYieldFrom方法來實現,而不是CombineDelay方法,這是更加令人困惑,我現在

回答

2

yield!支持在查詢中一定程度上,可以用在select通常是:

query { 
    for x in [5;2;0].AsQueryable() do 
    where (x > 1) 
    sortBy x 
    yield! [x; x-1] 
} |> Seq.toList // [2;1;5;4] 

然而,一般來說,你不能任意散佈查詢和序列操作,因爲它很難定義它們應該如何組成:

query { 
    for x in [1;2;3] do 
    where (x > 1) 
    while true do // error: can't use while (what would it mean?) 
    sortBy x 
} 

同樣:

query { 
    for x in [1;2;3] do 
    where (x > 1) 
    sortBy x 
    yield! ['a';'b';'c'] 
    yield! ['x';'y';'z'] // error 
}   

這是一種模糊,因爲目前還不清楚第二yield!是否是for循環內或事後追加一組元素。

所以最好想查詢,查詢和序列的序列,儘管這兩種計算式的支持一些相同的操作。

一般情況下,查詢運營商定製工作要素的角度來看,這樣表達的東西像工會或級聯是尷尬的,因爲他們在處理整個集合,而不是單個元素。但是,如果你願意,你可以創建補充說,花了序列concat運營商定製一個查詢構建器,雖然它可能會覺得有點不對稱:

open System.Linq 

type QB() = 
    member inline x.Yield v = (Seq.singleton v).AsQueryable() 
    member inline x.YieldFrom q = q 
    [<CustomOperation("where", MaintainsVariableSpace=true)>] 
    member x.Where(q:IQueryable<_>, [<ProjectionParameter>]c:Expressions.Expression<System.Func<_,_>>) = q.Where(c) 
    [<CustomOperation("sortBy", MaintainsVariableSpace=true)>] 
    member x.SortBy(q:IQueryable<_>, [<ProjectionParameter>]c:Expressions.Expression<System.Func<_,_>>) = q.OrderBy(c) 
    [<CustomOperation("select")>] 
    member x.Select(q:IQueryable<_>, [<ProjectionParameter>]c:Expressions.Expression<System.Func<_,_>>) = q.Select(c) 
    [<CustomOperation("concat")>] 
    member x.Concat(q:IQueryable<_>, q') = q.Concat(q') 
    member x.For(q:IQueryable<'t>, c:'t->IQueryable<'u>) = q.SelectMany(fun t -> c t :> seq<_>) // TODO: implement something more reasonable here 

let qb = QB() 

qb { 
    for x in ([5;2;0].AsQueryable()) do 
    where (x > 1) 
    sortBy x 
    select x 
    concat ([7;8;9].AsQueryable()) 
} |> Seq.toList 
1

這是查詢表達式在F#中的極佳參考:https://msdn.microsoft.com/en-us/library/hh225374.aspx

特別,我想從該網頁下面的例子中你想要做什麼:

let query1 = query { 
     for n in db.Student do 
     select (n.Name, n.Age) 
    } 

let query2 = query { 
     for n in db.LastStudent do 
     select (n.Name, n.Age) 
     } 

query2.Union (query1) 
+0

我已經知道如何「的毗連/聯盟」都查詢,這更多的是一個哲學問題。既然它已經可以完成了,爲什麼不能用傳統的'yield!'在其他計算表達式中使用,比如'Seq'和'List'? – Luiso