Skip to content

Instantly share code, notes, and snippets.

@sir-wabbit
Created November 1, 2018 04:25

Revisions

  1. @beer-avalanche beer-avalanche created this gist Nov 1, 2018.
    84 changes: 84 additions & 0 deletions shapely-POC.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,84 @@
    trait Iso[A, B] {
    def to(a: A): B
    def from(b: B): A
    }

    trait Derivable[F[_]] {
    type Fields[_]
    def fieldOf[A](name: String, value: F[A]): Fields[A]
    def fieldUnit: Fields[Unit]
    def fieldZip[A, B](left: Fields[A], right: Fields[B]): Fields[(A, B)]
    def fieldMap[A, B](fa: Fields[A])(f: Iso[A, B]): Fields[B]

    type Cases[_]
    def caseOf[A](name: String, fields: Fields[A]): Cases[A]
    def caseUnit: Cases[Nothing]
    def caseZip[A, B](left: Cases[A], right: Cases[B]): Cases[Either[A, B]]
    def caseMap[A, B](fa: Cases[A])(f: Iso[A, B]): Cases[B]

    def coproduct[A](name: String, cases: Cases[A]): F[A]
    def product[A](name: String, fields: Fields[A]): F[A]
    }

    trait Show[A] {
    def show(a: A): String
    }

    val showDerivable: Derivable[Show] = new Derivable[Show] {
    type Fields[A] = A => List[String]

    def fieldOf[A](name: String, value: Show[A]): Fields[A] =
    a => List(name + "=" + value.show(a))

    def fieldUnit: Fields[Unit] =
    a => Nil

    def fieldZip[A, B](left: Fields[A], right: Fields[B]): Fields[(A, B)] =
    { case (a, b) => left(a) ++ right(b) }

    def fieldMap[A, B](fa: Fields[A])(f: Iso[A, B]): Fields[B] =
    b => fa(f.from(b))

    type Cases[A] = A => String

    def caseOf[A](name: String, fields: Fields[A]): Cases[A] =
    a => name + "(" + fields(a).mkString(", ") + ")"

    def caseUnit: Cases[Nothing] =
    a => a

    def caseZip[A, B](left: Cases[A], right: Cases[B]): Cases[Either[A, B]] =
    ab => ab.fold(left, right)

    def caseMap[A, B](fa: Cases[A])(f: Iso[A, B]): Cases[B] =
    b => fa(f.from(b))

    def coproduct[A](name: String, cases: Cases[A]): Show[A] =
    a => cases(a)

    def product[A](name: String, fields: Fields[A]): Show[A] =
    a => name + "(" + fields(a).mkString(", ") + ")"
    }

    implicit val intShow: Show[Int] = a => a.toString
    implicit val boolShow: Show[Boolean] = a => a.toString

    final case class Foo(i: Int, b: Boolean)

    val fooShow = {
    import showDerivable._

    val fooIso = new Iso[(Int, Boolean), Foo] {
    def to(p: (Int, Boolean)): Foo = Foo(p._1, p._2)
    def from(p: Foo): (Int, Boolean) = (p.i, p.b)
    }

    product("Foo", fieldMap(fieldZip(
    fieldOf("i", implicitly[Show[Int]]),
    fieldOf("b", implicitly[Show[Boolean]])))(fooIso))
    }

    println(fooShow.show(Foo(1, true)))


    ///