Существуют ли какие-либо разумные аналоги LINQ (.NET) для Scala?
Аналоги LINQ в Scala?
Ответ 1
Это зависит от того, что именно вы подразумеваете под "LINQ". LINQ - это много чего.
Самый очевидный ответ: просто используйте порт .NET Scala. Это дает вам полный собственный доступ ко всему в .NET, который, очевидно, включает LINQ.
К сожалению, порт .NET Scala был сброшен пару лет назад. К счастью, он был снова поднят пару месяцев назад, причем официальное финансирование напрямую от Microsoft не меньше. Вы можете рассчитывать на выпуск когда-то в таймфрейме 2011/2012.
В любом случае, что такое LINQ?
Несколько функций, добавленных в .NET, а именно С# и VB.NET для LINQ. Они не являются технически частью LINQ, но являются необходимыми предпосылками: тип вывода, анонимные (структурные) типы, лямбда-выражения, типы функций (Func<T...>
и Action<T...>
) и деревья выражений. Все они были в Scala в течение долгого времени, большинство из них были там навсегда.
Также не является прямой частью LINQ, но в С# выражения запроса LINQ могут использоваться для генерации XML, для эмуляции XML-литералов VB.NET. Scala имеет XML-литералы, такие как VB.NET.
Более конкретно, LINQ
- спецификация для набора стандартных операторов запроса
- набор реализаций для этих операторов (т.е.
IQueryable
, LINQ-to-XML, LINQ-to-SQL, LINQ-to-Objects) - встроенный встроенный синтаксис для понимания запросов LINQ
- Монада
В Scala, как и в любом другом функциональном языке (а на самом деле также практически любом другом объектно-ориентированном языке), операторы запроса являются просто частью стандартного API-интерфейсов. В .NET у них немного странные имена, тогда как в Scala они имеют те же стандартные имена, что и у них на других языках: Select
is map
, Aggregate
is reduce
(или fold
), SelectMany
- flatMap
, Where
- filter
или withFilter
, orderBy
- sort
или sortBy
или sortWith
, и есть zip
, take
и takeWhile
и т.д. Таким образом, это касается как спецификации, так и реализации LINQ-to-Objects. Scala XML-библиотеки также реализуют API-интерфейсы коллекций, которые заботятся о LINQ-to-XML.
SQL API не встроены в Scala, но существуют сторонние API, которые реализуют API коллекции.
Scala также имеет специализированный синтаксис для этих API, но в отличие от Haskell, который пытается сделать их похожими на императивные C-блоки и С#, которые пытаются сделать их похожими на SQL-запросы, Scala пытается заставить их выглядеть for
. Они называются for
-пониманиями и эквивалентны пониманию запросов С# и пониманию монадов Haskell. (Они также заменяют С# foreach
и генераторы (yield return
)).
Но если вы действительно хотите узнать, есть ли аналоги для LINQ в Scala, вам сначала нужно указать, что именно вы подразумеваете под "LINQ". (И, конечно, если вы хотите знать, являются ли они "нормальными", вам также придется определить это.)
Ответ 2
Все расширения LINQ IEnumerable
доступны в Scala. Например:
Linq:
var total = orders
.Where(o => o.Customer == "myCustomer")
.SelectMany(o => o.OrderItems)
.Aggregate(0, (sum, current) => sum + current.Price * current.Count);
scala:
val total = orders
.filter(o => o.customer == "myCustomer")
.flatMap(o => o.orderItems)
.foldLeft(0)((s, c) => s + c.price * c.count)
Ответ 3
Слик
- это современный запрос к базе данных и библиотека доступа для Scala. (http://slick.typesafe.com/)
@table("COFFEES") case class Coffee(
@column("COF_NAME") name: String,
@column("SUP_ID") supID: Int,
@column("PRICE") price: Double
)
val coffees = Queryable[Coffee]
// for inserts use lifted embedding or SQL
val l = for {
c <- coffees if c.supID == 101
// ^ comparing Int to Int!
} yield (c.name, c.price)
backend.result( l, session )
.foreach { case (n, p) => println(n + ": " + p) }
Ответ 4
В Scala существует много ситуаций, где вы можете использовать монадические конструкции как своего рода язык запросов.
Например, чтобы запросить XML (в этом случае извлечь URL-адреса из ссылок в некоторых XHTML):
def findURLs(xml: NodeSeq): Seq[URL] =
for {
a <- xml \\ "a"
href <- a attribute "href"
url <- href.text
} yield URL(url)
Для аналога LINQ to SQL ближайшая вещь, вероятно, ScalaQuery. Чтобы снять пример прямо из документов:
val q4c = for {
u <- Users
o <- Orders if o.userID is u.id
} yield u.first ~ o.orderID