Skip to content

Instantly share code, notes, and snippets.

@koshelev
Last active August 29, 2015 14:28
Show Gist options
  • Save koshelev/549c15c16229723af4d3 to your computer and use it in GitHub Desktop.
Save koshelev/549c15c16229723af4d3 to your computer and use it in GitHub Desktop.
refined result
import cats.data.Xor
import shapeless._
import shapeless.ops.hlist.IsHCons
import shapeless.tag.@@
trait Predicate[P, T] extends Serializable { self =>
type Out
def apply(x: T) : Out
}
trait IsSuccess[T] {
def apply(t : T) : Boolean
}
object IsSuccess {
implicit def defaultInstance[T] : IsSuccess[??[T]] = new IsSuccess[??[T]] {
override def apply(t: ??[T]): Boolean = t.value
}
implicit def hconsInstance[H, L <: HList](implicit isHCons: IsHCons.Aux[L, H, _], success: IsSuccess[H]) : IsSuccess[L] = new IsSuccess[L] {
override def apply(t: L): Boolean = success( t.head )
}
}
trait And[A, B]
trait True
trait False
final case class ??[A](value: Boolean) extends AnyVal // use Boolean @@ A instead?
object Predicate {
type Aux[P, T, Out0] = Predicate[P, T] { type Out = Out0 }
implicit def andInstance[A, AOut, B, BOut, T]( implicit
ap: Predicate.Aux[A, T, AOut],
bp: Predicate.Aux[B, T, BOut],
as: IsSuccess[AOut],
bs: IsSuccess[BOut]) : Predicate.Aux[A And B, T, ??[And[A,B]] :: (AOut :: BOut :: HNil) :: HNil] =
new Predicate[A And B, T] {
type Out = ??[And[A,B]] :: (AOut :: BOut :: HNil) :: HNil
override def apply(x: T) = {
val a = ap(x)
val b = bp(x)
??[A And B]( as(a) && bs(b) ) :: (a :: b :: HNil) :: HNil
}
}
implicit def trueInstance[T] : Predicate.Aux[True, T, ??[True]] = new Predicate[True, T] {
type Out = ??[True]
override def apply(x: T) : Out = ??[True](true)
}
implicit def falseInstance[T] : Predicate.Aux[False, T, ??[False]] = new Predicate[False, T] {
override type Out = ??[False]
override def apply(x: T): ??[False] = ??[False](false)
}
def apply[P, T](implicit p: Predicate[P, T]): Predicate[P, T] = p
}
final class Refine[P] {
def apply[T, POut](t : T)(implicit predicate: Predicate.Aux[P, T, POut], isSuccess: IsSuccess[POut]) : Xor[predicate.Out, T @@ P] = {
val res = predicate(t)
if( isSuccess( res ) ) Xor.right( tag[P](t) ) else Xor.left( res )
}
}
object Demo extends App {
def refineT[P] = new Refine[P]
new Refine[False].apply("false")
new Refine[True].apply("true")
println( refineT[True And False].apply( "false" ) )
println( new Refine[True And True].apply( "true" ) )
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment