Skip to content

Instantly share code, notes, and snippets.

@hobwekiva
Last active April 26, 2017 19:21
Show Gist options
  • Save hobwekiva/d965fc3a3cb34fbf269f3ffd7b2c909a to your computer and use it in GitHub Desktop.
Save hobwekiva/d965fc3a3cb34fbf269f3ffd7b2c909a to your computer and use it in GitHub Desktop.
import cats.Applicative
import cats.instances.list._
import cats.instances.option._
import cats.syntax.functor._
import cats.Id
trait Instance[TC[_]] {
type Type
def value: Type
def typeclass: TC[Type]
}
object Instance {
implicit def apply[A, TC[_]](a: A)(implicit A: TC[A]): Instance[TC] = new Instance[TC] {
type Type = A
val value = a
val typeclass = A
}
}
trait I18n[F[_]] {
def formatInt(value: Int): F[String]
def formatBool(value: Boolean): F[String]
}
trait Format[A] { def format[F[_]](a: A)(implicit F: Applicative[F], I: I18n[F]): F[String] }
object Format {
def apply[A](implicit A: Format[A]): Format[A] = A
def universal[A]: Format[A] = new Format[A] {
def format[F[_]](a: A)(implicit F: Applicative[F], I: I18n[F]) = F.pure(a.toString)
}
implicit val showInt: Format[Int] = new Format[Int] {
def format[F[_]](a: Int)(implicit F: Applicative[F], I: I18n[F]) = I.formatInt(a)
}
implicit val showBool: Format[Boolean] = new Format[Boolean] {
def format[F[_]](a: Boolean)(implicit F: Applicative[F], I: I18n[F]) = I.formatBool(a)
}
implicit val showStr: Format[String] = universal[String]
}
sealed trait Formatter {
def format[F[_]](implicit I: I18n[F], F: Applicative[F]): F[String]
}
implicit final class I18nStringContext(val sc: StringContext) extends AnyVal {
def intersperse[A](a : List[A], b : List[A]): List[A] = a match {
case first :: rest => first :: intersperse(b, rest)
case _ => b
}
def i18n_[F[_]](args: Instance[Format]*)(implicit I: I18n[F], F: Applicative[F]): F[String] =
F.traverse(args.toList)(i => i.typeclass.format[F](i.value)(F, I))
.map(vars => intersperse(sc.parts.toList, vars).mkString(""))
def i18n(args: Instance[Format]*): Formatter = new Formatter {
def format[F[_]](implicit I: I18n[F], F: Applicative[F]): F[String] =
F.traverse(args.toList)(i => i.typeclass.format[F](i.value)(F, I))
.map(vars => intersperse(sc.parts.toList, vars).mkString(""))
}
}
// Obviously you wouldn't necessarily use Id.
implicit val i18nId: I18n[Id] = new I18n[Id] {
def formatInt(value: Int): Id[String] = value.toString
def formatBool(value: Boolean): Id[String] = value.toString
}
def f[F[_]: I18n: Applicative, A: Format](a: A): F[String] =
i18n"".format[F]
println(i18n_"${10 < 12} ${1 + 1}")
println(i18n"${10 < 12} ${1 + 1}".format[Id])
println(i18n_"${1}${2}${3}${4}${5}${6}${7}${8}${9}${10}${11}${12}${13}${14}${15}${16}${17}${18}${19}${20}${21}${22}${23}${24}${25}${26}${27}${28}${29}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment