Оптимальное представление выражений в F#

Я работаю над библиотекой для генерации SQL из выражений LINQ (в основном модифицированное подмножество LINQ-to-SQL). Я использую размеченные союзы для моделирования выражений SQL, но столкнулся с некоторыми (очевидными?) ограничениями. Я хочу сделать что-то вроде следующего (обратите внимание на последнюю строку):

type SqlSourceExpression =
    | Table of string
    | Join of JoinType * SqlSourceExpression * SqlSourceExpression * SqlExpression //ie, left, right, predicate

and SqlExpression =
    | Source of SqlSourceExpression
    | OrderBy of SqlExpression * SortDirection
    | Select of SqlSourceExpression * SqlExpression * OrderBy list //can't do this

Я мог бы сделать следующее:

type SqlOrderByExpression = SqlExpression * SortDirection

... и измените последние две строки на:

    | OrderBy of SqlOrderByExpression
    | Select of SqlSourceExpression * SqlExpression * SqlOrderByExpression list

Но это, кажется, имеет две проблемы:

  1. SqlOrderByExpression не является SqlExpression. Это затрудняет использование шаблона посетителя (может быть, здесь и кроется проблема?). Это означает, что при обходе выражения Select я не могу перебирать список порядка с помощью выражений, передающих каждое из них в Visit(expr:SqlExpression).

  2. SqlOrderByExpression — это просто псевдоним типа для кортежа, поэтому информация о типе не сохраняется. Это вредит читабельности IMO.

Есть ли лучший способ смоделировать это? Я попробовал маршрут наследования, но я думаю, что с DU НАМНОГО проще работать (за исключением отмеченной трудности).


person Daniel    schedule 09.12.2009    source источник
comment
Не знаю, будет ли это полезно, но полезная модель простых операторов доступна здесь: en.wikibooks.org/wiki/F_Sharp_Programming/   -  person Juliet    schedule 09.12.2009
comment
@ Джульетта - Спасибо. В этой статье есть несколько полезных моментов.   -  person Daniel    schedule 09.12.2009


Ответы (2)


Когда вы работаете с техникой FP (DU), вам не нужно запоминать шаблоны ООП, просто используйте функции высокого порядка (fold, map, zippers и т. д.).

Если вы просто хотите конкретизировать представление для вашего кода соответствия, есть активные шаблоны:

let (|OrderByTerm|OrderByList|_|)= function
  |OrderBy x -> Some (OrderByTerm x)
  |Select (_,_,xs) -> Some (OrderByList xs)
  |_ -> None
person ssp    schedule 09.12.2009

Я не уверен, почему SqlExpression, как разграниченный союз, имеет падежи для OrderBy и Select. Что разрешено входить внутрь OrderBy?

Я думаю, что дискриминированные профсоюзы делают это более трудным, чем это должно быть. Я думаю, что SqlSourceExpression, SqlOrderByExpression и SqlSelectExpression могут быть разных типов. Вы можете сделать их записями, если вас беспокоит, что кортежи трудно читать (это то, что я бы сделал в вашей ситуации).

Я думаю, что размеченное объединение SqlExpression пригодится, когда вы начнете представлять деревья выражений, такие как (1 + SUM(ISNULL(Value1, Value2))) / COUNT(*), где синтаксис более гибкий.

person Tim Robinson    schedule 09.12.2009
comment
OrderBys на самом деле довольно выразительны. Если вы хотите, вы можете написать order by case when table.col = value then 1 else 0 end DESC или даже подзапросы. Но в любом случае я полностью согласен: если нет бизнес-требований для обработки каждого пограничного случая, модель данных OP слишком тяжела для его целей. - person Juliet; 09.12.2009
comment
Хороший момент: SqlOrderByExpression будет содержать SqlExpression, но не будет самостоятельным SqlExpression. - person Tim Robinson; 09.12.2009
comment
@Juliet - Помимо того, что эта модель может быть слишком «тяжеловесной», вы бы моделировали эти выражения аналогичным образом? - person Daniel; 09.12.2009
comment
@Daniel: нет, я бы не стал. Определение SqlExpression выглядит некорректным, потому что ‹code›let x= OrderBy(Source(Table Users), ASC)‹/code› является допустимым F#, но, вероятно, не соответствует допустимому выражению SQL. Вместо того, чтобы пытаться создать всеобъемлющую модель SQL, я бы начал с малого: выбрал очень маленькое подмножество SQL (т. е. без подзапросов, предложений ORDER BY, ограниченных именем столбца и направлением, без производных таблиц и т. д.), а затем построил свой модель оттуда. Как только вы сможете представить ограниченное подмножество SQL, вам будет легче строить его оттуда. - person Juliet; 10.12.2009