Я читаю книгу Реальное функциональное программирование Tomas Petricek и Jon Skeet, и мне нелегко переваривать раздел по вычислению expressions1) (иначе монады).
Через эту книгу я узнал, что — вопреки моему предыдущему опыту — выражения запроса LINQ не ограничиваются IEnumerable
, но может работать над другими пользовательскими типами также. Это кажется очень интересным мне, и я задаюсь вопросом, существуют ли сценарии где синтаксис выражения запроса (from x in ... select ...
) было бы хорошее соответствие.
По-видимому, такие пользовательские типы называют типами вычисления, которые изображаются как являющийся по существу тем же самым как монады в Haskell. Я никогда не мог схватить, каковы точно монады, но согласно книге, они определяются посредством двух названных операций, связывают и возвращаются.
В функциональном программировании подписи типа этих двух операций были бы (я думаю):
// Bind : M -> (A' -> B') -> M
//
// Return : A' -> M
где M
имя одноместного типа.
В C# это соответствует:
Func< M, Func, M > Bind;
Func< A, M > Return;
Оказывается что LINQ's Enumerable.Select
(оператор проекции), имеет точно ту же подпись как связывать операция с M := IEnumerable
.
Используя это знание, я могу теперь записать пользовательский тип вычисления, который не является IEnumerable
:
// my custom computation type:
class Wrapped
{
// this corresponds to the Return operation:
public Wrapped(A value)
{
this.Value = value;
}
public readonly A Value;
}
static class Wrapped
{
// this corresponds to the Bind operation:
public static Wrapped Select(this Wrapped x, Func selector)
{
return new Wrapped(selector(x.Value));
}
}
И теперь я могу использовать Wrapped
в LINQ запрашивают выражения, например:
Wrapped wrapped = new Wrapped(41);
Wrapped answer = from x in wrapped // works on int values instead
select x + 1; // of Wrapped values!
Конечно, этот пример не очень полезен, но он демонстрирует, как выражения запроса могут быть сделаны сделать что-то еще, чем работа с наборами, например, обертывание и разворачивание значений с некоторым типом.
Вышеупомянутый тип вычисления не кажется очень полезным. Поэтому интересно, чем могло там быть другое разумное использование (помимо обработки наборов), это использует выражения запроса LINQ?
1) Раздел 12.4: "Представляя альтернативные рабочие процессы", начиная на странице 334.
Хотя мне не нравится это делать (потому что это немного похоже на жульничество), я думаю, что на этот раз мне придется ответить на свой вопрос.
Я подумал еще об этом. Мой вопрос был несколько наивным. Все сводится к тому, что выражения запроса LINQ (например, из
… в
… , где
… select
…), а также ] foreach
- это синтаксический сахар поверх другого, более простого синтаксиса.
foreach
работает со всем, что реализует метод IEnumerator
. IEnumerable
просто выполняет это условие.
Точно так же выражения запросов LINQ транслируются в соответствии с некоторыми четко определенными правилами, например из x в xs, где x> 0 select -x
становится xs.Where (x => x> 0) .Select (x => -x)
. Пока какой-либо тип реализует некоторые или все методы оператора запроса, этот тип можно использовать с LINQ практически для любых целей.
От меня остается вопрос: для чего на самом деле можно использовать LINQ, помимо обработки коллекций; и я думаю, что ответ будет «для очень небольшого другого», потому что структура выражений запросов LINQ довольно жесткая . Вам всегда понадобится из
… в
часть. Кажется, что select
… тоже нужен всегда. Если «язык» результирующих выражений не соответствует конкретному потенциальному сценарию, любое из других ключевых слов ( let
, orderby
, groupby
и т. Д. ) не улучшит ситуацию.LINQ был совершенно четко разработан с одной целью - это запрос данных, и полученная грамматика фактически ограничивает LINQ больше, чем это, вероятно, необходимо.
Я сравнил возможности LINQ для целей, отличных от запроса данных, с возможностями вычислительных выражений F #, и они кажутся более гибкими, поскольку требуемых ключевых слов не так много. Что делает их подходящими для большего количества сценариев.
LinqToTwitter использует LINQ необычным образом. Вещи в предложении 'from' не являются, по логике, перечислимыми типами. Взгляните на источник :)
Мысли:
IEnumerable
pull) из
( SelectMany
) и т. д., чтобы выбрать точки ветвления / слияния полностью , не связанные с перечислениями