Skip to content

Instantly share code, notes, and snippets.

@hobwekiva
Created November 1, 2018 04:25
Show Gist options
  • Save hobwekiva/f15132b9bde37632321818f3d901414e to your computer and use it in GitHub Desktop.
Save hobwekiva/f15132b9bde37632321818f3d901414e to your computer and use it in GitHub Desktop.
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)))
///
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment