Skip to content

Instantly share code, notes, and snippets.

@markhibberd
Created February 17, 2014 06:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markhibberd/9045633 to your computer and use it in GitHub Desktop.
Save markhibberd/9045633 to your computer and use it in GitHub Desktop.
import scalaz._, Scalaz._
import shapeless._
case class Codec[A](to: A => List[String], from: List[String] => String \/ (List[String], A)) {
def bimap[B](f: A => B, g: B => A): Codec[B] =
Codec[B](g andThen to, x => from(x).map(_.map(f)))
}
import scala.util.Try
import scala.util.{Success => TrySuccess}
import scala.util.{Failure => TryFailure}
object Codec extends TypeClassCompanion[Codec] {
implicit def IntCodec: Codec[Int] =
TryCodec[Int](_.toString, _.toInt)
implicit def StringCodec: Codec[String] =
ElementCodec[String](identity, _.right[String])
implicit def CodecTypeClass: ProductTypeClass[Codec] = new ProductTypeClass[Codec] {
def emptyProduct =
ConstCodec(HNil)
def product[A, T <: HList](A: Codec[A], T: Codec[T]) =
Codec(a => A.to(a.head) ++ T.to(a.tail), l => for {
ll <- A.from(l)
(m, v) = ll
mm <- T.from(m)
(n, u) = mm
} yield (n, v :: u))
def project[F, G](instance: => Codec[G], to : F => G, from : G => F) =
instance.bimap(from, to)
}
def ElementCodec[A](to: A => String, from: String => String \/ A) = {
import scala.collection.immutable._
Codec[A](x => List(to(x)), l => l match {
case x :: xs =>
from(x).map(a => xs -> a)
case _ =>
"Unexpected EOF.".left[(List[String], A)]
})
}
def ConstCodec[A](v: => A) =
Codec[A](_ => List(), xs => (xs, v).right[String])
def TryCodec[A](to: A => String, unsafe: String => A) =
ElementCodec[A](_.toString, x =>
Try(unsafe(x)) match {
case TrySuccess(v) => v.right[String]
case TryFailure(e) => e.getMessage.left[A]
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment