Hablando funcionalmente, LINQ no es más que una simplificación sintáctica para expresar mónadas. Linq to Objects (Lista de comprensiones - incluso esto ya sería extremadamente útil), de lo que ha estado hablando, es solo una posible aplicación de esto (similar a List-Monad en Haskell).
Si se escribe
from x in expr1
from y in expr2
select x + y
No es más que
do
x <- expr1
y <- expr2
return $ x + y
en Haskell.
Lo concreto que se hace depende de LINQ proveedores definidos por el usuario (extensión-Métodos) de los cuales Linq.Enumerable
es sólo una aplicación que implica IEnumerable
s.
Al proporcionar uno, puede crear una semántica LINQ completamente nueva para sus tipos.
Ejemplo: Dado un tipo Option
para los cálculos que pueden fallar (valores que aceptan valores anulables), se podría definir un proveedor de Linq para consultar sobre ellos.
public static class MaybeExtensions
{
public static Option<T> ToMaybe<T>(this T value)
{
return Option<T>.Some(value);
}
public static Option<U> SelectMany<T, U>(
this Option<T> m,
Func<T, Option<U>> k)
{
return !m.IsNone ? Option<U>.None : k(m.Value);
}
public static Option<V> SelectMany<T, U, V>(
this Option<T> m,
Func<T, Option<U>> k,
Func<T, U, V> s)
{
return m.SelectMany(x => k(x).SelectMany(y => s(x, y).ToMaybe()));
}
}
Esto sería ahora nos permitirá escribir dicho código:
var sum = from x in ReadNumber("x")
from y in ReadNumber("y")
select x + y;
El cálculo sólo devolverá un valor si todos los cálculos tuvieron éxito y de lo contrario se producirá un error en la primera fallar uno.
En combinación con los árboles de expresión, LINQ puede ser extremadamente potente y le permite expresar -
- base de datos de accesos
- asíncrono flujo Programm
- quizá, Mónadas
- listas por comprensión
- recursiva Analizadores de descenso
- Continuaciones
- Mini-idiomas
- cálculos paralelos (PLINQ)
Algunos enlaces:
Combinado con los combinadores de punto fijo, Linq proporciona un mini-lenguaje funcional completo (Linq raytracer).
Tenga en cuenta que Scala y F # ambos tienen conceptos similares en para-comprensiones y expresiones de cálculo que ambos son abstracciones monádicos:
Scala:
for (x <- expr1
y <- expr2) yield x + y
F #:
monad {
let! x = expr1
let! y = expr2
return x + y
}
Gracias por la información. Voy a investigar esas pistas. – Joe
Realmente, muy buen resumen con un ejemplo agradable y fácil de comprender. +1 –
Continuando en el enlace raytracer, aquí está el mismo raytracer implementado por completo en una sola declaración LINQ: http://tirania.org/blog/archive/2007/Nov-16.html – JulianR