¿Análogos de LINQ en Scala?
(4)
¿Hay algún análogo cuerdo a LINQ (.NET) para Scala?
Depende de qué quiere decir exactamente con "LINQ". LINQ es muchas cosas.
La respuesta más obvia sería: simplemente use el puerto .NET de Scala. Le brinda acceso nativo completo a todo en .NET, que obviamente incluye LINQ.
Desafortunadamente, el puerto .NET de Scala fue descartado hace un par de años. Afortunadamente, fue recogido nuevamente hace un par de meses, sin financiación oficial directamente de Microsoft. Puede esperar un lanzamiento en algún momento dentro del marco de tiempo de 2011/2012.
De todos modos, ¿qué es LINQ?
Un par de características fueron agregadas a .NET y específicamente a C # y VB.NET para LINQ. No son técnicamente parte de LINQ, pero son requisitos previos necesarios: tipo de inferencia, tipos anónimos (estructurales), expresiones lambda, tipos de funciones ( Func<T...>
y Action<T...>
) y árboles de expresiones. Todos estos han estado en Scala durante mucho tiempo, la mayoría han estado allí para siempre.
Además, no forma parte directamente de LINQ, pero en C #, las expresiones de consulta LINQ se pueden usar para generar XML, para emular los literales XML de VB.NET. Scala tiene literales XML, como VB.NET.
Más específicamente, LINQ es
- una especificación para un conjunto de operadores de consulta estándar
- un conjunto de implementaciones para esos operadores (es decir,
IQueryable
, LINQ-to-XML, LINQ-to-SQL, LINQ-to-Objects) - una sintaxis incorporada incorporada para la comprensión de consultas LINQ
- una mónada
En Scala, como en casi cualquier otro lenguaje funcional (y de hecho también en casi cualquier otro lenguaje orientado a objetos, también), los operadores de consulta son simplemente parte de la API de colecciones estándar. En .NET, tienen nombres un tanto extraños, mientras que en Scala, tienen los mismos nombres estándar que tienen en otros idiomas: Select
es map
, Aggregate
es reduce
(o fold
), SelectMany
es flatMap
, Where
is filter
o withFilter
, orderBy
es sort
or sortBy
u sortWith
, y hay zip
, take
y takeWhile
y así sucesivamente. Entonces, eso se ocupa tanto de la especificación como de la implementación de LINQ-to-Objects. Las bibliotecas XML de Scala también implementan las API de colecciones, que se encargan de LINQ-to-XML.
Las API de SQL no están integradas en Scala, pero hay API de terceros que implementan la API de recopilación.
Scala también tiene una sintaxis especializada para esas API, pero a diferencia de Haskell, que intenta hacer que se vean como bloques C imperativos y C #, que intenta hacer que se vean como consultas SQL, Scala intenta hacer que se vean como bucles. Se necesitan comprensión y son equivalentes a las comprensiones de las consultas de C # y las mónadas de comprensión de Haskell. (También reemplazan los foreach
y generadores de C # ( yield return
)).
Pero si realmente quiere saber si hay análogos para LINQ en Scala, primero tendrá que especificar qué quiere decir exactamente con "LINQ". (Y por supuesto, si quiere saber si están "cuerdos", también tendrá que definir eso).
Hay muchas situaciones en Scala donde puede usar construcciones monádicas como un tipo de lenguaje de consulta.
Por ejemplo, para consultar XML (en este caso, extraer URL de enlaces en algunos XHTML):
def findURLs(xml: NodeSeq): Seq[URL] =
for {
a <- xml // "a"
href <- a attribute "href"
url <- href.text
} yield URL(url)
Para un análogo de LINQ a SQL, lo más parecido es probablemente ScalaQuery . Para levantar un ejemplo directamente de los documentos:
val q4c = for {
u <- Users
o <- Orders if o.userID is u.id
} yield u.first ~ o.orderID
Todas las extensiones de LINQ IEnumerable
están disponibles en Scala. Por ejemplo:
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)
Mancha
es una biblioteca moderna de consulta y acceso a bases de datos para 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) }