Skip to content

Instantly share code, notes, and snippets.

@hisui
Last active February 1, 2017 04:22
Show Gist options
  • Save hisui/42c63818284fdab5338365a1f5c0d46c to your computer and use it in GitHub Desktop.
Save hisui/42c63818284fdab5338365a1f5c0d46c to your computer and use it in GitHub Desktop.
scalaVersion := "2.11.8"
resolvers ++= Seq(
Resolver.sonatypeRepo("releases"),
Resolver.sonatypeRepo("snapshots")
)
libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.2"
object Main extends App {
val a = Seq("a", "b", "c")
// syntax #1
{
import MyCoproductSyntax1._
for (username <- a; password <- a) {
UserService.authenticate(username, password).foldTo[Unit]
.caseOf[Authenticated] (_ => println("You just logged in!"))
.caseOf[UserNotFound] (_ => println("Who are you?"))
.caseOf[UserBanned] (_ => println("Go back home."))
.caseOf[BadCredential] (_ => println("Don't hack me."))
.end
}
}
// syntax #2
{
import MyCoproductSyntax2._
for (username <- a; password <- a) {
UserService.authenticate(username, password) foldWith (
(_: Authenticated ) => println("You just logged in!"),
(_: UserNotFound ) => println("Who are you?"),
(_: UserBanned ) => println("Go back home."),
(_: BadCredential ) => println("Don't hack me.")
)
}
}
}
import shapeless.Coproduct
import shapeless.ops.coproduct.Remove
object MyCoproductSyntax1 {
implicit class CoproductOps[C <: Coproduct](val raw: C) extends AnyVal {
def foldTo[U] = new CoproductFold[U, C](Right(raw))
}
class CoproductFold[U, C <: Coproduct](val raw: Either[U, C]) extends AnyVal {
def caseOf[H](f: H => U)(implicit rm: Remove[C, H]): CoproductFold[U, rm.Rest] =
raw.fold(
e => new CoproductFold(Left(e)),
e => new CoproductFold(rm(e).left map f)
)
def end(implicit ev: C =:= CNil): U = raw.left.get
}
}
import shapeless.HList
import shapeless.HNil
import shapeless.`::`
import shapeless.CNil
import shapeless.Coproduct
import shapeless.Generic
import shapeless.ops.coproduct.Remove
object MyCoproductSyntax2 {
trait ZipFold[C <: Coproduct, L <: HList, Z] {
type Out >: Z
def apply(c: C, list: L): Out
}
object ZipFold {
implicit def case_1[A1, A2 >: A1, H, T <: HList, C1 <: Coproduct, C2 <: Coproduct]
(implicit rm: Remove.Aux[C1, H, C2], next: ZipFold[C2, T, A2]) = new ZipFold[C1, (H => A2) :: T, A1] {
type Out = next.Out
def apply(c: C1, list: (H => A2) :: T): Out = rm(c).fold(list.head, next(_, list.tail))
}
implicit def case_0[A] = new ZipFold[CNil, HNil, A] {
type Out = A
def apply(c: CNil, list: HNil): Out = throw new IllegalStateException("..bug? (*_*;)")
}
}
implicit class CoproductOps[C <: Coproduct](val raw: C) extends AnyVal {
def foldWith[U, P <: Product, L <: HList](cases: P)
(implicit gen: Generic.Aux[P, L], zip: ZipFold[C, L, Nothing]) = zip(raw, gen.to(cases))
}
}
import shapeless.Coproduct
import shapeless.CNil
import shapeless.:+:
case class Authenticated()
case class BadCredential()
case class UserNotFound()
case class UserBanned()
object UserService {
type AuthenticateResult =
( Authenticated
:+: BadCredential
:+: UserNotFound
:+: UserBanned
:+: CNil
)
def authenticate(username: String, password: String): AuthenticateResult =
(username, password) match {
case ("a", "a") => Coproduct[AuthenticateResult](Authenticated())
case ("a", _) => Coproduct[AuthenticateResult](BadCredential())
case ("b", _) => Coproduct[AuthenticateResult](UserBanned())
case (_ , _) => Coproduct[AuthenticateResult](UserNotFound())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment