Функционально говоря, LINQ - не что иное, как синтаксическое упрощение выражения монад. Linq to Objects (списки-понимания - даже это уже было бы чрезвычайно полезно), о которых вы говорили, это всего лишь одно возможное применение этого (аналогично List-Monad в Haskell).
Если вы напишите
from x in expr1
from y in expr2
select x + y
это не что иное, как
do
x <- expr1
y <- expr2
return $ x + y
в Хаскеле.
Конкретное действие зависит от определенных пользователем Linq-провайдеров (Extension-Methods), из которых Linq.Enumerable
является лишь одной реализацией, включающей IEnumerable
s.
Предоставляя его, вы можете создать совершенно новую семантику LINQ для ваших типов.
Пример: учитывая тип Option
для вычислений, которые могут завершиться ошибкой (значения, допускающие значение NULL), можно определить провайдера Linq для запроса к ним.
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()));
}
}
Теперь это позволило бы нам написать такой код:
var sum = from x in ReadNumber("x")
from y in ReadNumber("y")
select x + y;
Вычисление вернет значение только в случае успешного выполнения всех вычислений и в противном случае произойдет сбой первого неудачного вычисления.
В сочетании с деревьями выражений Linq может быть чрезвычайно мощным и позволяет вам выражать -
- Доступ к базе данных
- Асинхронный поток программ
- Может быть, Монады
- Список понятий
- парсеры рекурсивного спуска
- Продолжения
- Мини-языки
- Параллельные вычисления (PLinq)
Некоторые ссылки:
В сочетании с комбинаторами с фиксированной точкой Linq предоставляет полный функциональный мини-язык ( Linq raytracer ).
Обратите внимание, что Scala и F # оба имеют сходные понятия в выражениях для вычислений и вычислениях, оба являются монадическими абстракциями:
Scala:
for (x <- expr1
y <- expr2) yield x + y
F #:
monad {
let! x = expr1
let! y = expr2
return x + y
}