Пример #1
0
        /// <summary>
        /// Merge a sequence of producers into a single producer
        /// </summary>
        /// <remarks>The merged producer completes when all component producers have completed</remarks>
        /// <param name="ms">Sequence of producers to merge</param>
        /// <returns>Merged producers</returns>
        public static Producer <RT, OUT, A> merge <RT, OUT, A>(Seq <Producer <RT, OUT, A> > ms) where RT : struct, HasCancel <RT>
        {
            return(from e in Producer.lift <RT, OUT, RT>(runtime <RT>())
                   from x in Producer.enumerate2 <RT, OUT>(go(e))
                   from _ in Producer.yield <RT, OUT>(x)
                   select default(A));

            async IAsyncEnumerable <OUT> go(RT env)
            {
                var queue   = new ConcurrentQueue <OUT>();
                var wait    = new AutoResetEvent(true);
                var running = true;

                // Create a consumer that simply awaits a value and then puts it in our concurrent queue
                // to be re-yielded
                var enqueue = Consumer.awaiting <RT, OUT>()
                              .Map(x =>
                {
                    queue.Enqueue(x);
                    wait.Set();
                    return(default(A));
                })
                              .ToConsumer();

                // Compose the enqueue Consumer with the Producer to create an Effect that can be run
                var mme = ms.Map(m => m | enqueue).Strict();

                // Run the producing effects
                // We should NOT be awaiting these
                var mmt = mme.Map(m => m.RunEffect().Run(env).AsTask());

                // When all tasks are done, we're done
                // We should NOT be awaiting this
                #pragma warning disable CS4014
                Task.WhenAll(mmt.ToArray())
                .Iter(_ =>
                {
                    running = false;
                    wait.Set();
                });
                #pragma warning restore CS4014

                // Keep processing until we're cancelled or all of the Producers have stopped producing
                while (running && !env.CancellationToken.IsCancellationRequested)
                {
                    await wait.WaitOneAsync(env.CancellationToken).ConfigureAwait(false);

                    while (queue.TryDequeue(out var item))
                    {
                        yield return(item);
                    }
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Folds values coming down-stream, when the predicate returns true the folded value is yielded
        /// </summary>
        /// <param name="Initial">Initial state</param>
        /// <param name="Fold">Fold operation</param>
        /// <param name="UntilValue">Predicate</param>
        /// <returns>A pipe that folds</returns>
        public static Producer <RT, S, Unit> FoldWhile <RT, S, A>(this Producer <RT, S, A> ma, S Initial, Func <S, A, S> Fold, Func <S, bool> WhileState)
            where RT : struct, HasCancel <RT>
        {
            var state = Initial;

            return(ma.Bind(
                       x =>
            {
                state = Fold(state, x);
                if (WhileState(state))
                {
                    return Producer.Pure <RT, S, Unit>(unit);
                }
                else
                {
                    var nstate = state;
                    state = Initial;
                    return Producer.yield <RT, S>(nstate);
                }
            }));
        }
Пример #3
0
        /// <summary>
        /// Folds values coming down-stream, when the predicate returns true the folded value is yielded
        /// </summary>
        /// <param name="Initial">Initial state</param>
        /// <param name="Fold">Fold operation</param>
        /// <param name="UntilValue">Predicate</param>
        /// <returns>A pipe that folds</returns>
        public static Producer <RT, S, Unit> FoldUntil <RT, S, A>(this Producer <RT, S, A> ma, S Initial, Func <S, A, S> Fold, Func <A, bool> UntilValue)
            where RT : struct, HasCancel <RT>
        {
            var state = Initial;

            return(ma.Bind(
                       x =>
            {
                if (UntilValue(x))
                {
                    var nstate = state;
                    state = Initial;
                    return Producer.yield <RT, S>(nstate);
                }
                else
                {
                    state = Fold(state, x);
                    return Producer.Pure <RT, S, Unit>(unit);
                }
            }));
        }