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

syntax.CatsSyntax.scala Maven / Gradle / Ivy

The newest version!
package jjm.syntax

import jjm.DependentMap
import jjm.DotMap
import jjm.DotF

import cats.~>
import cats.Applicative
import cats.Foldable
import cats.Order
import cats.Monad
import cats.Monoid
import cats.data.Ior
import cats.data.NonEmptyList
import cats.arrow.Arrow
import cats.implicits._

trait CatsSyntax {

  implicit class RichFoldable[F[_]: Foldable, A](val fa: F[A]) {

    def counts: Map[A, Int] = fa.foldMap(a => Map(a -> 1))

    def sum(implicit N: Numeric[A]): A = fa.foldLeft(N.fromInt(0))(N.plus)

    def meanOpt(implicit N: Numeric[A]): Option[Double] = {
      val (sum, count) = fa.foldLeft(N.fromInt(0), N.fromInt(0)) {
        case ((curSum, curCount), a) => (N.plus(curSum, a), N.plus(curCount, N.fromInt(1)))
      }
      if (count == 0) None else Some(N.toDouble(sum) / N.toDouble(count))
    }

    def proportion(predicate: A => Boolean): Double =
      fa.foldLeft((0, 0)) {
        case ((trues, total), a) =>
          if (predicate(a)) (trues + 1, total + 1)
          else (trues, total + 1)
      } match { case (trues, total) => trues.toDouble / total }

    def maxima(implicit o: Order[A]): List[A] =
      fa.foldLeft(List.empty[A]) { (maxes, a) =>
        maxes.headOption.fold(a :: Nil) { max =>
          if(a > max) a :: Nil
          else if(a.eqv(max)) a :: maxes
          else maxes
        }
      }.reverse

    def maximaBy[B: Order](f: A => B): List[A] =
      fa.foldLeft(List.empty[(A, B)]) { (maxes, a) =>
        val key = f(a)
        maxes.headOption.fold((a -> key) :: Nil) { case (_, maxKey) =>
          if(key > maxKey) (a -> key) :: Nil
          else if(key < maxKey) maxes
          else (a -> key) :: maxes
        }
      }.reverse.map(_._1)

    def minima(implicit o: Order[A]): List[A] =
      maxima(Order.reverse(o))

    def minimaBy[B](f: A => B)(implicit o: Order[B]): List[A] =
      maximaBy(f)(Order.reverse(o))
  }

  implicit class RichIorSame[A](val ior: Ior[A, A]) { // TODO AnyVal
    def mergeM[F[_]: Applicative](f: (A, A) => F[A]) = ior.fold(
      Applicative[F].pure,
      Applicative[F].pure,
      f
    )
  }

  // TODO
  // implicit class RichNonEmptyList[A](val x: NonEmptyList[A]) { // TODO AnyVal
  //   def maximaNel(implicit o: Order[A]): NonEmptyList[A]
  //   def maximaNelBy[B](f: A => B)(implicit o: Order[B]): NonEmptyList[A]
  //   def minimaNel(implicit o: Order[A]): NonEmptyList[A] =
  //     maximaNel(o.reverse)
  //   def minimaNelBy[B](f: A => B)(implicit o: Order[B]): NonEmptyList[A] =
  //     maximaNelBy(f)(o.reverse)
  // }

  implicit class RichNested[M[_], F[_], A](val x: M[F[A]]) { // TODO AnyVal
    def flatFoldMapM[B: Monoid](f: A => M[B])(implicit M: Monad[M], F: Foldable[F]): M[B] =
      M.flatMap(x)(_.foldMapM(f))
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy