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

teststate.data.Sack.scala Maven / Gradle / Ivy

The newest version!
package teststate.data

import acyclic.file
import teststate.typeclass._
import Profunctor.ToOps.toProfunctorOps
import Sack._

sealed abstract class Sack[-I, +A] {

//  def isEmpty(i: I): Boolean

  /** Whether this is provably empty.
    *
    * A coproduct could return an empty set for some inputs but it isn't provable and so isn't considered empty.
    */
  def isEmpty: Boolean

  final def nonEmpty = !isEmpty
}

object Sack {

  final case class Value[+A](value: A) extends Sack[Any, A] {
    override def isEmpty = false
  }

  final case class Product[-I, +A](contents: Vector[Sack[I, A]]) extends Sack[I, A] {
    override def isEmpty = contents.isEmpty
  }

  final case class CoProduct[-I, +A](name: NameFn[I], produce: I => Sack[I, A]) extends Sack[I, A] {
    override def isEmpty = false
  }

  val empty: Sack[Any, Nothing] =
    Product(Vector.empty)

  implicit val sackInstanceEmpty: Empty[Sack[Any, Nothing]] =
    Empty(Sack.empty)

  def append[A, B](a: Sack[A, B], b: Sack[A, B]): Sack[A, B] =
    if (a.isEmpty)
      b
    else if (b.isEmpty)
      a
    else
      (a, b) match {
        case (Product(p), Product(q)) => Product(p ++ q)
        case (p         , Product(q)) => Product(p +: q)
        case (Product(p), q         ) => Product(p :+ q)
        case (p         , q         ) => Product(Vector.empty :+ p :+ q)
      }

  implicit val sackInstanceProfunctor: Profunctor[Sack] =
    new Profunctor[Sack] {

      override def rmap[A, B, C](m: Sack[A, B])(f: B => C): Sack[A, C] =
        m match {
          case Value(b)        => Value(f(b))
          case Product(s)      => Product(s map (_ rmap f))
          case CoProduct(n, p) => CoProduct(n, p(_) rmap f)
        }

      override def dimap[A, B, C, D](m: Sack[A, B])(g: C => A, f: B => D): Sack[C, D] =
        m match {
          case Value(b)        => Value(f(b))
          case Product(s)      => Product(s map (_.dimap(g, f)))
          case CoProduct(n, p) => CoProduct(n cmap g, c => p(g(c)).dimap(g, f))
        }
    }

  implicit def sackInstanceConditionalR[A, B, I](implicit c: Conditional[B, I]): Conditional[Sack[A, B], I] =
    Conditional((s, f) => s.rmap(c.when(_, f)))

  implicit def sackInstanceDisplay[A, B](implicit display: Display[B]): Display[Sack[A, B]] =
    Display { sack =>
      val sb = new StringBuilder
      def add(s: String): Unit = {
        if (sb.nonEmpty)
          sb append '\n'
        sb append s
        ()
      }
      def go(s: Sack[A, B]): Unit =
        s match {
          case Value(b)        => add(display(b))
          case Product(ss)     => ss foreach go
          case CoProduct(n, _) => add(n(None).value)
        }
      go(sack)
      sb.result()
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy