All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scalaz.iteratee.EnumerateeT.scala Maven / Gradle / Ivy

The newest version!
package scalaz
package iteratee

import Iteratee._
import Ordering._

trait EnumerateeT[O, I, F[_]] { self =>
  def apply[A]: StepT[I, F, A] => IterateeT[O, F, StepT[I, F, A]]

  def run(enumerator: EnumeratorT[O, F])(implicit M: Monad[F]): EnumeratorT[I, F] = {
    new EnumeratorT[I, F] {
      def apply[A] = (s: StepT[I, F, A]) => iterateeT((self[A](s) &= enumerator).run)
    }
  }
}

object EnumerateeT extends EnumerateeTFunctions

trait EnumerateeTFunctions {
  /**
   * Applies a function to each input element and feeds the resulting outputs to the inner iteratee.
   */
  def map[O, I, F[_] : Monad](f: O => I): EnumerateeT[O, I, F] =
    new EnumerateeT[O, I, F] {
      def apply[A] = {
        def loop = step andThen cont[O, F, StepT[I, F, A]]
        def step: (Input[I] => IterateeT[I, F, A]) => (Input[O] => IterateeT[O, F, StepT[I, F, A]]) = {
          k => in =>
            in(
              el = e => k(elInput(f(e))) >>== doneOr(loop)
              , empty = cont(step(k))
              , eof = done(scont(k), in)
            )
        }

        doneOr(loop)
      }
    }

  def flatMap[O, I, F[_]: Monad](f: O => EnumeratorT[I, F]): EnumerateeT[O, I, F] =
    new EnumerateeT[O, I, F] {
      def apply[A] = {
        def loop(step: StepT[I, F, A]): IterateeT[O, F, StepT[I, F, A]] = {
          step.fold(
            cont = contf => cont[O, F, StepT[I, F, A]] {
              (_: Input[O]).map(e => f(e)).fold(
                el    = en => en.apply(step) >>== loop,
                empty = contf(emptyInput) >>== loop,
                eof   = done(step, emptyInput)
              )
            },
            done = (a, _) => done(sdone(a, emptyInput), emptyInput)
          )
        }

        loop
      }
    }

  def collect[O, I, F[_] : Monad](pf: PartialFunction[O, I]): EnumerateeT[O, I, F] =
    new EnumerateeT[O, I, F] {
      def apply[A] = {
        def loop = step andThen cont[O, F, StepT[I, F, A]]
        def step: (Input[I] => IterateeT[I, F, A]) => (Input[O] => IterateeT[O, F, StepT[I, F, A]]) = {
          k => in =>
            in(
              el = e => if (pf.isDefinedAt(e)) k(elInput(pf(e))) >>== doneOr(loop) else cont(step(k))
              , empty = cont(step(k))
              , eof = done(scont(k), in)
            )
        }

        doneOr(loop)
      }
    }

  def filter[E, F[_] : Monad](p: E => Boolean): EnumerateeT[E, E, F] =
    new EnumerateeT[E, E, F] {
      def apply[A] = {
        def loop = step andThen cont[E, F, StepT[E, F, A]]
        def step: (Input[E] => IterateeT[E, F, A]) => (Input[E] => IterateeT[E, F, StepT[E, F, A]]) = {
          k => in =>
            in(
              el = e =>
                if (p(e)) k(in) >>== doneOr(loop)
                else cont(step(k))
              , empty = cont(step(k))
              , eof = done(scont(k), in)
            )
        }

        doneOr(loop)
      }
    }

  /**
   * Uniqueness filter. Assumes that the input enumerator is already sorted.
   */
  def uniq[E: Order, F[_]: Monad]: EnumerateeT[E, E, F] =
    new EnumerateeT[E, E, F] {
      def apply[A] = {
        def step(s: StepT[E, F, A], last: Input[E]): IterateeT[E, F, A] =
          s mapCont { k =>
            cont { in =>
              val inr = in.filter(e => last.forall(l => Order[E].order(e, l) != EQ))
              k(inr) >>== (step(_, in))
            }
          }

        s => step(s, emptyInput).map(sdone(_, emptyInput))
      }
    }

  /**
   * Zips with the count of elements that have been encountered.
   */
  def zipWithIndex[E, F[_]: Monad]: EnumerateeT[E, (E, Long), F] =
    new EnumerateeT[E, (E, Long), F] {
      def apply[A] = {
        type StepEl = Input[(E, Long)] => IterateeT[(E, Long), F, A]
        def loop(i: Long) = (step(_: StepEl, i)) andThen (cont[E, F, StepT[(E, Long), F, A]])
        def step(k: StepEl, i: Long): (Input[E] => IterateeT[E, F, StepT[(E, Long), F, A]]) = {
          (in: Input[E]) =>
            in.map(e => (e, i)).fold(
              el = e => k(elInput(e)) >>== doneOr(loop(i + 1))
              , empty = cont(step(k, i))
              , eof = done(scont(k), in)
            )
        }

        doneOr(loop(0))
      }
    }

  def group[E, F[_], G[_]](n: Int)(implicit F: Applicative[F], FE: Monoid[F[E]], G: Monad[G]): EnumerateeT[E, F[E], G] =
    new EnumerateeT[E, F[E], G] {
      def apply[A] = take[E, F](n).up[G].sequenceI.apply[A]
    }

  def splitOn[E, F[_], G[_]](p: E => Boolean)(implicit F: Applicative[F], FE: Monoid[F[E]], G: Monad[G]): EnumerateeT[E, F[E], G] =
    new EnumerateeT[E, F[E], G] {
      def apply[A] = {
        (takeWhile[E, F](p).up[G] flatMap (xs => drop[E, G](1).map(_ => xs))).sequenceI.apply[A]
      }
    }

  def cross[E1, E2, F[_]: Monad](e2: EnumeratorT[E2, F]): EnumerateeT[E1, (E1, E2), F] =
    new EnumerateeT[E1, (E1, E2), F] {
      def apply[A] = {
        def outerLoop(step: StepT[(E1, E2), F, A]): IterateeT[E1, F, StepT[(E1, E2), F, A]] =
          for {
            outerOpt   <- head[E1, F]
            sa         <- outerOpt match {
                            case Some(e) =>
                              val pairingIteratee = EnumerateeT.map[E2, (E1, E2), F]((a: E2) => (e, a)).apply(step)
                              val nextStep = (pairingIteratee &= e2).run
                              iterateeT[(E1, E2), F, A](nextStep) >>== outerLoop

                            case None    =>
                              done[E1, F, StepT[(E1, E2), F, A]](step, eofInput)
                          }
          } yield sa

        outerLoop
      }
    }


  def doneOr[O, I, F[_] : Applicative, A](f: (Input[I] => IterateeT[I, F, A]) => IterateeT[O, F, StepT[I, F, A]]): StepT[I, F, A] => IterateeT[O, F, StepT[I, F, A]] = {
    (s: StepT[I, F, A]) => s.mapContOr(k => f(k), done(s, emptyInput))
  }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy