Ответ 1
SelectMany
в С# соответствует привязка в Haskell (>>=)
или flatMap
в Scala. Подпись >>=
в Haskell:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
поэтому bind - это операция, используемая для построения одного монадического значения из другого.
В случае С# m
в вышеуказанной сигнатуре IEnumerable
, IObservable
, IQueryable
и т.д. Для IEnumerable
, SelectMany
, следовательно,
IEnumerable<A> -> (A -> IEnumerable<B>) -> IEnumerable<B>
или в С#
public static IEnumerable<B> SelectMany<A, B>(this IEnumerable<A> first, Func<A, IEnumerable<B>> selector)
Значение bind зависит от типа monad, для IEnumerable каждый элемент во входной последовательности используется для создания новой последовательности, а результирующая последовательность последовательностей сглаживается для создания выходной последовательности.
Существует еще одна формулировка связывания, которая может сделать это более ясным. Хотя монады часто описываются с точки зрения реализации bind, монады также должны поддерживать две другие операции: map
и join
.
map
соответствует Select в С# и выглядит так:
map :: Monad m => (a -> b) -> (ma -> m b)
так что это "сохраняющий структуру" способ поднятия регулярной функции над монадическим значением.
join
имеет тип
join :: Monad m => m m a -> m a
поэтому join используется для выравнивания вложенных монадических значений. В С# это будет выглядеть как
public static IEnumerable<A> Join<A>(this IEnumerable<IEnumerable<A>> nested)
bind
может быть реализован в терминах карты и присоединения как
m >>= f = join (map f m)
поэтому для ответа на исходный вопрос SelectMany
соответствует bind
или flatMap
на других языках. Привязка не просто сглаживается, но может рассматриваться как преобразование, за которым следует сглаживание вложенных монадических значений (например, последовательности в случае IEnumerable<T>
). join
для IEnumerable<T>
не существует в текущих расширениях linq.