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

syntax.StdSyntax.scala Maven / Gradle / Ivy

The newest version!
package jjm.syntax

import jjm.Duad

import cats.Functor
import cats.Order
import cats.data.Ior
import cats.implicits._

trait StdSyntax {

  implicit class RichPair[F[_], A, B](val x: F[(A, B)]) { // TODO AnyVal
    def mapFirst[C](f: A => C)(implicit F: Functor[F]): F[(C, B)] =
      x.map { case (a, b) => f(a) -> b }
    def mapSecond[C](f: B => C)(implicit F: Functor[F]): F[(A, C)] =
      x.map { case (a, b) => a -> f(b) }
  }

  implicit class RichList[A](val a: List[A]) { // TODO AnyVal
    def remove(i: Int) = a.take(i) ++ a.drop(i + 1)
  }

  implicit class RichVector[A](val a: Vector[A]) { // TODO AnyVal
    def remove(i: Int) = a.take(i) ++ a.drop(i + 1)
  }

  implicit class RichOption[A](val a: Option[A]) { // TODO AnyVal
    // more readable alternatives to forall/exists
    def emptyOr(predicate: A => Boolean): Boolean = a.forall(predicate)
    def nonEmptyAnd(predicate: A => Boolean): Boolean = a.exists(predicate)

    def ifEmpty[B](b: => B): Option[B] = a match {
      case Some(_) => None
      case None    => Some(b)
    }
  }

  implicit class RichMap[A, B](val x: Map[A, B]) { // TODO AnyVal
    def mapVals[C](f: B => C): Map[A, C] = x.transform { case (_, v) => f(v) }
    def zipValues[C](y: Map[A, C]) = {
      val keys = x.keySet.intersect(y.keySet)
      keys.iterator.map(k => k -> (x(k) -> y(k))).toMap
    }
    def normalize(implicit N: Numeric[B]): Map[A, Double] = {
      val total = N.toDouble(x.values.sum)
      mapVals(v => N.toDouble(v) / total)
    }

    // superseded by `Align` once that's in cats
    def merge[C](y: Map[A, C]): Map[A, Ior[B, C]] = {
      val keySet = x.keySet ++ y.keySet
      keySet.iterator.map { key =>
        key -> Ior.fromOptions(x.get(key), y.get(key)).get // should always work
      }.toMap
    }
  }

  final implicit class RichAny[A](val a: A) { // TODO AnyVal
    def <|[B](f: A => B): B = f(a)

    def const: Any => A = _ => a

    def onlyIf(p: (A => Boolean)): Option[A] = Some(a).filter(p)
    def ifNot(p: (A => Boolean)): Option[A] = Some(a).filterNot(p)

    def <->(b: A)(implicit o: Order[A]): Duad[A] = Duad(a, b)
  }

  // implicit class RichTry[A](val t: Try[A]) extends AnyVal {
  //   // TODO probably nope, maybe after adding in log4cats or something
  //   def toOptionLogging(logger: Logger): Option[A] = t match {
  //     case Success(a) =>
  //       Some(a)
  //     case Failure(e) =>
  //       val sw = new StringWriter()
  //       val pw = new PrintWriter(sw, true)
  //       e.printStackTrace(pw)
  //       logger.error(e.getLocalizedMessage + "\n" + sw.getBuffer.toString)
  //       None
  //   }
  // }

  implicit class RichListCompanion[A](val companion: List.type) { // TODO AnyVal

    def unfold[A, B](a: A, f: A => Option[(B, A)]): List[B] = f(a) match {
      case None                   => Nil
      case Some((head, tailToGo)) => head :: unfold(tailToGo, f)
    }

    def unfold[A, B](a: A, f: PartialFunction[A, (B, A)]): List[B] =
      unfold(a, f.lift)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy