Tech Off Post

Single Post Permalink

View Thread: LINQ Where; fold vs bind...
  • User profile image


    This post refers to some Going Deep videos...

    Greg told in his video about shape, wrap and roll.

    LINQ Select many is "wrap" and Aggregate is "roll", right?

    LINQ Where have this kind of signature:

    public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 

    So... As Bart said in his video, "where" could be done with SelectMany.

    • public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector);

    I'll try...It will be something like this:

    return source.SelectMany(s => Enumerable.Repeat(s, predicate(s) ? 1 : 0));

    But.... as Ralf said in his video, "where" could be done with Aggregate.

    • public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func);

    I'll try...It will be something like this:

    return source.Aggregate((a, s) => predicate(s) ? a.Concat(Enumerable.Repeat(s, 1)):a);

    Now... Can we do Aggregate with SelectMany?

    No? Can you prove it?

    It shouldn't be possible, as monads are about shap, wrap (=bind, here: SelectMany) and roll (here: Aggregate)?

    SelectMany seems to be easy to do with Aggregate:

    return source.Aggregate((a, s) => a.Concat(selector(s)));

    Am I cheating here by using Concat? That will aggregate again inside the same container(monad). Will it use SelectMany inside?

    I could do SelectMany with Aggregate by exiting the monad and go back again (so I will cause the side effect to exit the monad and break the continuation), right? So:

    // SelectMany:
    M<A> -> (A -> M<B>) -> M<B>
    // Aggregate:
    M<A> -> B -> (B -> A -> B) -> B
    // Aggregate (if accumulator would be type of M<B>):
    M<A> -> M<B> -> (M<B> -> A -> M<B>) -> M<B>
    // this Aggregate without initial value:
    M<A> -> (M<B> -> A -> M<B>) -> M<B>
    // This is very near to select many, you can handle the extra parameter in the inner func as you like...

    So I can use IEnumerable<T> as accumulator (or could even a Func<...>). On the other hand, LINQ-methods are not pure... e.g. SelectMany is not pure monadic bind: it has some overloads.