Выражения запросов F# дают

Я учусь F# и сейчас я читаю о выражениях вычислений и выражениях запросов для использования с поставщиками типов SQL. Я выполнял несколько простых задач, и в какой-то момент мне нужно было объединить (Union) 2 запроса, моя первая мысль после прочтения о yield в последовательностях и списках нужно было сделать то же самое внутри выражения запроса следующим образом:

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

это был неверный код, тогда мой второй подход заключался в том, чтобы "конкатить" их, используя:

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

или используя Linq's Concat функционировать так: (query {...}).Concat(query {...}), Как это сделать пришло из ответа на этот вопрос

Оба вышеупомянутых подхода работают с одним отличием, хотя, используя seq будет выполнять 2 запроса SQL, а Concat работает только тот, который понятен.

Мой вопрос: почему нет yield поддерживается в выражениях запросов?


РЕДАКТИРОВАТЬ:

После дальнейшего расследования я добрался до документов MSDN и увидел Yield а также YieldFrom методы реализованы, но не Combine а также Delay методы, что сейчас еще более запутанно для меня

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

Это отличный справочник для выражений запросов в 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)
Другие вопросы по тегам