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

proptics.syntax.FoldSyntax.scala Maven / Gradle / Ivy

package proptics.syntax

import cats.Monoid
import cats.syntax.eq._
import cats.syntax.semigroup._

import proptics.Fold_
import proptics.internal.Forget
import proptics.rank2types.Rank2TypeFoldLike

trait FoldSyntax {
  implicit final def foldElementOps[S, T, A](fold: Fold_[S, T, A, A]): FoldElementOps[S, T, A] = FoldElementOps(fold)
}

final case class FoldElementOps[S, T, A](private val fold: Fold_[S, T, A, A]) extends AnyVal {
  /** narrow the focus of a [[Fold_]] to a single element */
  def single(i: Int): Fold_[S, T, A, A] = filterByIndex(_ === i)

  /** traverse elements of a [[Fold_]] whose index satisfy a predicate */
  def filterByIndex(predicate: Int => Boolean): Fold_[S, T, A, A] =
    foldWhileIndex(predicate)

  /** select the first n elements of a [[Fold_]] */
  def take(i: Int): Fold_[S, T, A, A] = filterByIndex(_ < i)

  /** select all elements of a [[Fold_]] except first n ones */
  def drop(i: Int): Fold_[S, T, A, A] = filterByIndex(_ >= i)

  /** take longest prefix of elements of a [[Fold_]] that satisfy a predicate */
  def takeWhile(predicate: A => Boolean): Fold_[S, T, A, A] =
    foldWhile(predicate, take = true)

  /** drop longest prefix of elements of a [[Fold_]] that satisfy a predicate */
  def dropWhile(predicate: A => Boolean): Fold_[S, T, A, A] =
    foldWhile(predicate, take = false)

  private[FoldElementOps] def foldWhile(predicate: A => Boolean, take: Boolean): Fold_[S, T, A, A] =
    Fold_(new Rank2TypeFoldLike[S, T, A, A] {
      override def apply[R: Monoid](forget: Forget[R, A, A]): Forget[R, S, T] = {
        val runForget = forget.runForget

        Forget(s =>
          fold
            .foldLeft(s)((true, Monoid[R].empty)) { case ((b, r), a) =>
              val acc = b && predicate(a)
              val result =
                if (acc)
                  if (take) r |+| runForget(a) else r
                else if (take) r
                else r |+| runForget(a)
              (acc, result)
            }
            ._2)
      }
    })

  private[FoldElementOps] def foldWhileIndex(predicate: Int => Boolean): Fold_[S, T, A, A] =
    Fold_(new Rank2TypeFoldLike[S, T, A, A] {
      override def apply[R: Monoid](forget: Forget[R, A, A]): Forget[R, S, T] = {
        val runForget = forget.runForget

        Forget(s =>
          fold
            .foldLeft(s)((0, Monoid[R].empty)) { case ((i, r), a) =>
              val acc = predicate(i)
              val result = if (acc) r |+| runForget(a) else r
              (i + 1, result)
            }
            ._2)
      }
    })
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy