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

net.arya.util.NonEmptySet.scala Maven / Gradle / Ivy

The newest version!
package net.arya.util

import scalaz.Isomorphism.{<~>, IsoFunctorTemplate}
import scalaz._, Scalaz._, Ordering._

object EmptySet {
  def unapply[A](s: Set[A]): Boolean = s.isEmpty
}

final class NonEmptySet[A] private[util](val head: A, val tail: Set[A]) {

  override def toString = "NonEmpty" + toSet.toString

  def toISet(implicit O: Order[A]): ISet[A] = ISet.fromFoldable(this)
  def toSet: Set[A] = tail + head
  def toList: List[A] = toSet.toList
  def toNEL: NonEmptyList[A] = NonEmptyList(head, tail.toSeq: _*)
  def size = tail.size + 1

  def insert(a: A): NonEmptySet[A] = NonEmptySet(head, tail + a - head)
  def delete(a: A): Set[A] = toSet - a
  def +(a: A): NonEmptySet[A] = insert(a)
  def -(a: A): Set[A] = delete(a)

  def map[B](f: A => B) = {
    val fhead: B = f(head)
    NonEmptySet(fhead, (tail map f) - fhead)
  }

  def flatMap[B](f: A => NonEmptySet[B]): NonEmptySet[B] = {
    val fhead = f(head)
    val ftails = tail map f
    import scalaz.std.set._
    NonEmptySet(fhead.head, fhead.tail union ftails.map(_.toSet).suml - fhead.head)
  }

  def contains(x: A): Boolean = (x == head) || tail.contains(x)
  def toMap[K,V](implicit ev: A <:< (K,V)) = toSet.toMap
  def filter(p: A => Boolean): Set[A] = toSet.filter(p)
}

object NonEmptySet {
  def apply[A](head: A, tail: Set[A]): NonEmptySet[A] =
    new NonEmptySet(head, tail - head)

  def apply[A](head: A, tail: A*): NonEmptySet[A] = apply(head, tail.toSet)

  def unapply[A](s: Set[A]): Option[NonEmptySet[A]] = s.isEmpty.fold(none, NonEmptySet(s.head, s.tail).some)

  def argmaxesBy[F[_],A,B](fa: F[A])(f: A => B)(implicit F: Foldable1[F], ord: math.Ordering[B]): NonEmptySet[A] =
    F.foldMapLeft1[A,(NonEmptySet[A],Option[B])](fa)(a => (NonEmptySet(a),Some(f(a)))) {
      case (maxes @ (as, bs @ Some(b0)), a) =>
        val b = f(a)
        fromInt(ord.compare(b,b0)) match {
          case GT => // a > max
            NonEmptySet(a) -> Some(b)
          case EQ => // a = max
            (as insert a, bs)
          case LT => // a < max
            maxes
        }
    } ._1

  implicit val nonEmptySetInstance: Foldable1[NonEmptySet] with Functor[NonEmptySet] with Pointed[NonEmptySet] with Plus[NonEmptySet] =
    new Foldable1[NonEmptySet] with Functor[NonEmptySet] with Pointed[NonEmptySet] with Plus[NonEmptySet] {
      override def plus[A](a: NonEmptySet[A], b: ⇒ NonEmptySet[A]): NonEmptySet[A] =
        NonEmptySet(a.head, a.tail + b.head ++ b.tail)

      override def foldMap1[A, B](fa: NonEmptySet[A])(f: (A) ⇒ B)(implicit F: Semigroup[B]): B =
        implicitly[Foldable[Set]].foldMap1Opt(fa.toSet)(f).get

      override def foldMapRight1[A, B](fa: NonEmptySet[A])(z: (A) ⇒ B)(f: (A, ⇒ B) ⇒ B): B =
        implicitly[Foldable[Set]].foldMapRight1Opt(fa.toSet)(z)(f).get

      override def map[A, B](fa: NonEmptySet[A])(f: (A) ⇒ B): NonEmptySet[B] =
        NonEmptySet(f(fa.head), fa.tail.map(f))

      override def point[A](a: A): NonEmptySet[A] =
        NonEmptySet(a)
    }

  implicit def nonEmptySetSemigroup[A]: Semigroup[NonEmptySet[A]] = nonEmptySetInstance.semigroup[A]
//  implicit def nonEmptySetShow[A:Show]: Show[NonEmptySet[A]] = foldableShow[NonEmptySet,A]("NESet(", ", ", ")")
  implicit def nonEmptySetOrder[A:Order]: Order[NonEmptySet[A]] = Order[Set[A]].contramap(_.toSet)

//  private def foldableShow[F[_]:Foldable,A:Show](prefix: String, separator: String, suffix: String): Show[F[A]] =
//    Show.show[F[A]] { fa ⇒
//      Cord.stringToCord(prefix) |+|
//        Cord.mkCord(Cord.stringToCord(separator), fa.foldLeft[List[Cord]](Nil)( (l,a) ⇒ a.show :: l ).reverse: _*) |+|
//        Cord.stringToCord(suffix)
//    }

  val oneAndNesIso: NonEmptySet <~> OneAnd[Set,?] =
    new IsoFunctorTemplate[NonEmptySet, OneAnd[Set,?]] {
      def to[A](fa: NonEmptySet[A]): OneAnd[Set,A] = OneAnd[Set,A](fa.head, fa.tail)
      def from[A](ga: OneAnd[Set,A]): NonEmptySet[A] = NonEmptySet(ga.head, ga.tail)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy