When using HList with GADTs I am having to cast using asInstanceOf[H]. Is there a way to avoid the cast? - scala

Given 2 GADT Algebras which know about each other and 2 interpreters that are mutually recursive, I am having issues having to cast from type A to type h <: HList even though in the context of the pattern match, it should be implied that type A is type h.
Is there a way to avoid the asInstanceOf[h] call in the interpreter?
abstract class KvpHList[H<:HList]
object KvpNil extends KvpHList[HNil]
case class KvpCons[H <: A :: T,A, T<:HList](head: KvpValue[A], tail: KvpHList[T])(implicit isHCons: IsHCons.Aux[H,A,T]) extends KvpHList[H] {
val hCons: IsHCons.Aux[H,A,T] = isHCons
}
abstract class KvpValue[A]
case object StringData extends KvpValue[String]
case class HListData[H <:HList](member: KvpHList[H]) extends KvpValue[H]
def hListInterpreter[H<:HList](hList: KvpHList[H]): H => String = {
hList match {
case KvpNil => (hNil: H) => "Nil"
case cons: KvpCons[H,a,t]=> {
implicit val hCons = cons.hCons
(input: H) => {
s"${kvpInterpreter(cons.head)(input.head)} :: ${hListInterpreter(cons.tail)(input.tail)}"
}
}
}
}
def kvpInterpreter[A](kvpValue: KvpValue[A]): A => String = {
kvpValue match {
case StringData => (str: String) => str
case h: HListData[h] => {
(input: A) => { // tried (input: h) as well
val toString: h => String = hListInterpreter(h.member)
toString(input.asInstanceOf[h]) // <--- CASTING :(
}
}
}
}
kvpInterpreter(HListData(KvpCons(StringData, KvpNil))).apply("Hello" :: HNil)

Since H in KvpCons is uniquely determined by A and T, KvpCons can be parametrized with two type parameters rather than three.
Type-level pattern matching is type classes
abstract class KvpHList[H <: HList]
object KvpNil extends KvpHList[HNil]
case class KvpCons[A, T <: HList](head: KvpValue[A], tail: KvpHList[T]) extends KvpHList[A :: T]
abstract class KvpValue[A]
case object StringData extends KvpValue[String]
case class HListData[H <: HList](member: KvpHList[H]) extends KvpValue[H]
trait HListInterpreter[H <: HList] {
def apply(hList: KvpHList[H]): H => String
}
object HListInterpreter {
implicit val nil: HListInterpreter[HNil] = new HListInterpreter[HNil] {
override def apply(hList: KvpHList[HNil]): HNil => String = _ => "Nil"
}
implicit def cons[A, T <: HList](implicit
headKvpInterpreter: KvpInterpreter[A],
tailHListInterpreter: HListInterpreter[T]
): HListInterpreter[A :: T] = new HListInterpreter[A :: T] {
override def apply(hList: KvpHList[A :: T]): A :: T => String = hList match {
case cons: KvpCons[_, _] => input => s"${headKvpInterpreter(cons.head)(input.head)} :: ${tailHListInterpreter(cons.tail)(input.tail)}"
}
}
}
def hListInterpreter[H <: HList](hList: KvpHList[H])(implicit hListInterp: HListInterpreter[H]): H => String = hListInterp(hList)
trait KvpInterpreter[A] {
def apply(kvpValue: KvpValue[A]): A => String
}
object KvpInterpreter {
implicit val string: KvpInterpreter[String] = new KvpInterpreter[String] {
override def apply(kvpValue: KvpValue[String]): String => String = str => str
}
implicit def hList[H <: HList : HListInterpreter]: KvpInterpreter[H] = new KvpInterpreter[H] {
override def apply(kvpValue: KvpValue[H]): H => String = kvpValue match {
case h: HListData[H] => input => {
val toString: H => String = hListInterpreter(h.member)
toString(input)
}
}
}
}
def kvpInterpreter[A](kvpValue: KvpValue[A])(a: A)(implicit kvpInterp: KvpInterpreter[A]): String = kvpInterp(kvpValue)(a)

Related

How to extract types from a tuple that implements a typeclass

Function a can receive single argument or a tuple, these arguments need to be members of typeclass StringIdentifiable
How to extract and decompose tuple type into types that also have instances of the typeclass
#typeclass trait StringIdentifiable[M] {
def identify(id: M): String
}
def a[K: StringIdentifiable] (k:K){
k match{
case (k1) =>
implicitly[StringIdentifiable[K]].identify(k1)
case (k1,k2) =>
implicitly[StringIdentifiable[k1.type]].identify(k1)
implicitly[StringIdentifiable[k2.type]].identify(k2)
}
I get error in the second match:
Could not find an instance of StringIdentifiable for k1.type
k1.type, k2.type are singleton types. Try
#typeclass trait StringIdentifiable[M] {
def identify(id: M): String
}
object StringIdentifiable {
implicit def one[K]: StringIdentifiable[K] = ???
implicit def two[K1: StringIdentifiable, K2: StringIdentifiable]: StringIdentifiable[(K1, K2)] = {
new StringIdentifiable[(K1, K2)] {
override def identify(id: (K1, K2)): String = id match {
case (k1,k2) =>
implicitly[StringIdentifiable[K1]].identify(k1)
implicitly[StringIdentifiable[K2]].identify(k2)
???
}
}
}
}
def a[K: StringIdentifiable](k:K): String = implicitly[StringIdentifiable[K]].identify(k)
You can do this with shapeless. For instance:
import shapeless._, ops.hlist._
object MyPoly extends Poly2 {
implicit def foo[A] = at[A, StringIdentifiable[A]]( (a, f) => f.identify(a) )
}
def a[K: StringIdentifiable, L <: HList, O <: HList](k: K)(
implicit
gen: Generic.Aux[K, L], // decompose K into HList L
lift: LiftAll.Aux[StringIdentifiable, L, O], // find an instance of StringIdentifiable for every element of L
zip: ZipWith[L, O, MyPoly.type] // zip L with its typeclass instances and map the results with the polymorphic function MyPoly
): String :: zip.Out = {
val l = gen.to(k)
val o = lift.instances
implicitly[StringIdentifiable[K]].identify(k) :: zip(l, o)
}
implicit def id1[A,B]: StringIdentifiable[(A, B)] = _ => "1"
implicit val id2: StringIdentifiable[String] = _ => "2"
implicit val id3: StringIdentifiable[Int] = _ => "3"
a(("foo", 42)) // 1 :: 2 :: 3 :: HNil
A full solution to your problem (IIUC) probably consists of using shapeless to automatically generate StringIdentifiable instances for all tuples.
trait StringIdentifiable[M] {
def identify(id: M): String
}
object StringIdentifiable {
object MyPoly extends Poly2 {
implicit def foo[A] = at[A, StringIdentifiable[A]]( (a, f) => f.identify(a) )
}
implicit def mkSI[K, L <: HList, O <: HList](
implicit
tup: IsTuple[K],
gen: Generic.Aux[K, L],
lift: LiftAll.Aux[StringIdentifiable, L, O],
zip: ZipWith[L, O, MyPoly.type]
): StringIdentifiable[K] = {
val o = lift.instances
k => {
val l = gen.to(k)
zip(l, o).mkString("(", ", ", ")")
}
}
}

Phantom existential types in Scala

I'm trying to write a value class that wraps Scala collection's Map and provides an alternative get. I'm trying to use a phantom type in the value class and tag the Key with the same type using the method member. If the result of member is Some(k) then the user should be able to call get(k) and get a V instead of an Option[V].
import scala.collection.{Map => M}
class Key[PH, K] private (val k: K) extends AnyVal
object Key {
def apply[PH, K](k: K): Key[PH, K] = new Key(k)
}
class Map[PH, K, V] private (val m: M[K, V]) extends AnyVal {
def member(k: K): Option[Key[PH, K]] = m.get(k).map(_ => Key(k))
def get(key: Key[PH, K]): V = m.get(key.k).get
}
object Map {
def apply[PH, K, V](m: M[K, V]): Map[PH, K, V] = new Map(m)
}
def withMap[K, V, T](m: M[K, V])(cont: (Map[PH, K, V] forSome { type PH }) => T): T = cont(Map(m))
withMap(M("a" -> "a")){ m =>
m.member("a") match {
case Some(v) => println(m.get(v))
case None => println(":(")
}
}
But currently it fails compiling with the following error:
found : Key[PH(in value $anonfun),String] where type +PH(in value $anonfun)
required: Key[PH(in value cont),String]
case Some(v) => println(m.get(v))
How can I convince scalac that the PHs are the same?
Destructure the existential:
withMap(M("a" -> "a")) { case m =>
m.member("a") match {
case Some(v) => println(m.get(v))
case None => println(":(")
}
}
This abbreviates
withMap(M("a" -> "a")) { case m: Map[ph, String, String] => // name the phantom type ph, name the map m =>
m.member("a") match {
case Some(v) => println(m.get(v))
case None => println(":(")
}
}
The destructuring allows m to be given a non-existential type in terms of a newly introduced type variable. This means that every occurrence of m can now have the same type.
Phantom types are meaningless. You should say what you mean: every Key belongs to a certain Map:
import scala.collection.immutable.Map // it is not safe to use Maps in general!
class KeyedMap[K, V](val m: Map[K, V]) extends AnyVal {
import KeyedMap._
def member(k: K): Option[Key[K, V, m.type]] = m.get(k).map { _ => new Key[K, V, m.type](k) }
def fromKey(k: Key[K, V, m.type]): V = m(k.k)
}
object KeyedMap {
// vvvvvvvvvvvvvv requires this parameter to be <something>.type
class Key[K, +V, M <: Map[K, V] with Singleton] private[KeyedMap](val k: K) extends AnyVal
}
object Test {
def main(args: String*): Unit = {
val m = new KeyedMap(Map("a" -> "b"))
m.member("a") match {
case Some(v) => println(m.fromKey(v))
case None => println(":(")
}
}
}

Type safe type combinations with shapeless

Having the following code:
import shapeless.{::, Generic, HList, HNil, Lazy}
object Problem {
trait In {
def bar: Double
}
trait A {
def foo: Int
type I <: In
}
/////////////////////////////////////////////////////
final case class A1In(d: Double) extends In {
override def bar: Double = 1.1 + d
}
final case class A1() extends A {
override def foo: Int = 1
override type I = A1In
}
final case class A2In(d: Double) extends In {
override def bar: Double = 1.1 + d
}
final case class A2() extends A {
override def foo: Int = 1
override type I = A2In
}
final case class AListIn[T <: HList](items: T)(implicit ev: isIn[T]) extends In {
override def bar = 1.1
}
final case class AList[T <: HList](items: T)(implicit ev: isA[T]) extends A {
override def foo: Int = 555
override type I = AListIn[???]
}
trait isA[T] {
def aux_foo(value: T): Int
}
trait isIn[T] {
def aux_bar(value: T): Double
}
/////////////////////////////////////////////////////
def alloc(a: A): In = ????
def usage() = {
val a1: A1 = A1()
val a2: A2 = A2()
val l: AList[::[A1, ::[A2, ::[A1, HNil]]]] = AList(a1 :: a2 :: a1 :: HNil)
val a1In: A1In = A1In(1.2)
val a2In: A2In = A2In(9.3)
val lIn: AListIn[::[A2In, ::[A1In, HNil]]] = AListIn(a2In :: a1In :: HNil)
}
}
How can I fix it so it works as expected?
E.g how do I get correct type in place of ??? which is a proper type HList being result of applying isA -> isIn type mapping. The mapping must follow the natural association of A -> In mapping defined as type I <: In in trait A
And how to implement alloc function which for any concrete instance of In will produce corresponding instance of A?
Should concrete implementations of In be path dependent types of corresponding As?
Below is the code for isA the code for isIn is analogous
trait isA[T] {
def aux_foo(value: T): Int
}
object isA {
// "Summoner" method
def apply[T](implicit enc: isA[T]): isA[T] = enc
// "Constructor" method
def instance[T](func: T => Int): isA[T] = new isA[T] {
override def aux_foo(value: T): Int = func(value)
}
implicit def a1Encoder: isA[A1] = instance(i => 4)
implicit def a2Encoder: isA[A2] = instance(i => 9)
implicit def hnilEncoder: isA[HNil] = instance(hnil => 0)
implicit def hlistEncoder[H, T <: HList](implicit
hInstance: Lazy[isA[H]],
tInstance: isA[T]
): isA[H :: T] = instance {
case h :: t => hInstance.value.aux_foo(h) + tInstance.aux_foo(t)
}
implicit def genericInstance[A, R](implicit
generic: Generic.Aux[A, R],
rInstance: Lazy[isA[R]]
): isA[A] = instance { value => rInstance.value.aux_foo(generic.to(value)) }
}

What is the purpose of the emptyCoproduct and coproduct methods of the TypeClass trait in Shapeless

It is not fully clear to me what is the purpose of the emptyCoProduct and coproduct methods of the TypeClass trait in Shapeless.
When would one use the TypeClass trait instead of the ProductTypeClass?
What are some examples of ways those two methods would be implemented?
Suppose I've got a simple type class:
trait Weight[A] { def apply(a: A): Int }
object Weight {
def apply[A](f: A => Int) = new Weight[A] { def apply(a: A) = f(a) }
}
And some instances:
implicit val stringWeight: Weight[String] = Weight(_.size)
implicit def intWeight: Weight[Int] = Weight(identity)
And a case class:
case class Foo(i: Int, s: String)
And an ADT:
sealed trait Root
case class Bar(i: Int) extends Root
case class Baz(s: String) extends Root
I can define a ProductTypeClass instance for my type class:
import shapeless._
implicit object WeightTypeClass extends ProductTypeClass[Weight] {
def emptyProduct: Weight[HNil] = Weight(_ => 0)
def product[H, T <: HList](hw: Weight[H], tw: Weight[T]): Weight[H :: T] =
Weight { case (h :: t) => hw(h) + tw(t) }
def project[F, G](w: => Weight[G], to: F => G, from: G => F): Weight[F] =
Weight(f => w(to(f)))
}
And use it like this:
scala> object WeightHelper extends ProductTypeClassCompanion[Weight]
defined object WeightHelper
scala> import WeightHelper.auto._
import WeightHelper.auto._
scala> implicitly[Weight[Foo]]
res0: Weight[Foo] = Weight$$anon$1#4daf1b4d
scala> implicitly[Weight[Bar]]
res1: Weight[Bar] = Weight$$anon$1#1cb152bb
scala> implicitly[Weight[Baz]]
res2: Weight[Baz] = Weight$$anon$1#74930887
But!
scala> implicitly[Weight[Root]]
<console>:21: error: could not find implicit value for parameter e: Weight[Root]
implicitly[Weight[Root]]
^
This is a problem—it makes our automated type class instance derivation pretty much useless for ADTs. Fortunately we can use TypeClass instead:
implicit object WeightTypeClass extends TypeClass[Weight] {
def emptyProduct: Weight[HNil] = Weight(_ => 0)
def product[H, T <: HList](hw: Weight[H], tw: Weight[T]): Weight[H :: T] =
Weight { case (h :: t) => hw(h) + tw(t) }
def project[F, G](w: => Weight[G], to: F => G, from: G => F): Weight[F] =
Weight(f => w(to(f)))
def emptyCoproduct: Weight[CNil] = Weight(_ => 0)
def coproduct[L, R <: Coproduct]
(lw: => Weight[L], rw: => Weight[R]): Weight[L :+: R] = Weight {
case Inl(h) => lw(h)
case Inr(t) => rw(t)
}
}
And then:
scala> object WeightHelper extends TypeClassCompanion[Weight]
defined object WeightHelper
scala> import WeightHelper.auto._
import WeightHelper.auto._
scala> implicitly[Weight[Root]]
res0: Weight[Root] = Weight$$anon$1#7bc44e19
All the other stuff above still works as well.
To sum up: Shapeless's Coproduct is a kind of abstraction over ADTs, and in general you should provide instances of TypeClass for your type classes instead of just ProductTypeClass whenever possible.
As of shapeless 2.3.2, the above example doesn't seem to compile. here's the updated one for future reference:
import shapeless._
import shapeless.test._
trait Weight[A] { def apply(a: A): Int }
object Weight {
def apply[A](f: A => Int) = new Weight[A] { def apply(a: A) = f(a) }
}
case class Foo(i: Int, s: String)
sealed trait Root
case class Bar(i: Int) extends Root
case class Baz(s: String) extends Root
object Base {
implicit val stringWeight: Weight[String] = Weight(_.size)
implicit def intWeight: Weight[Int] = Weight(identity)
}
object ProductTC {
object WeightHelper extends ProductTypeClassCompanion[Weight] {
object typeClass extends ProductTypeClass[Weight] {
def emptyProduct: Weight[HNil] = Weight(_ => 0)
def product[H, T <: HList](hw: Weight[H], tw: Weight[T]): Weight[H :: T] =
Weight { case (h :: t) => hw(h) + tw(t) }
def project[F, G](w: => Weight[G], to: F => G,from: G => F): Weight[F] =
Weight(f => w(to(f)))
}
}
import Base._
import WeightHelper._
implicitly[Weight[Foo]]
implicitly[Weight[Bar]]
implicitly[Weight[Baz]]
illTyped("implicitly[Weight[Root]]")
}
object TC {
object WeightTypeClass extends TypeClassCompanion[Weight] {
object typeClass extends TypeClass[Weight] {
def emptyProduct: Weight[HNil] = Weight(_ => 0)
def product[H, T <: HList](hw: Weight[H], tw: Weight[T]): Weight[H :: T] =
Weight { case (h :: t) => hw(h) + tw(t) }
def project[F, G](w: => Weight[G], to: F => G, from: G => F): Weight[F] =
Weight(f => w(to(f)))
def emptyCoproduct: Weight[CNil] = Weight(_ => 0)
def coproduct[L, R <: Coproduct]
(lw: => Weight[L], rw: => Weight[R]): Weight[L :+: R] = Weight {
case Inl(h) => lw(h)
case Inr(t) => rw(t)
}
}
}
import Base._
import WeightTypeClass._
implicitly[Weight[Root]]
}

Generic `implicit` operators for monads?

This is part programming exercise and part practical.
I'd like to build an operator | in this example such that:
val x: Option[Int] = _
def fail: Nothing = _
val result = x | fail
I have this so far and it doesn't compile:
import language.implicitConversions
import scala.util.{Try, Success, Failure}
trait OrAbleFacilitator[T] {
def apply[U](t: T, u: => U): U
}
implicit val OptionOrAbleFacilitator = new OrAbleFacilitator[Option[T]] {
def apply[U, U >: T](t: Option[T], u: => U): U = {
t match {
case Some(v) => v
case _ => u
}
}
}
implicit val TryOrAbleFacilitator = new OrAbleFacilitator[Try[T]] {
def apply[U, U >: T](t: Try[T], u: => U): U = {
t match {
case Success(v) => v
case _ => u
}
}
}
implicit class OrAble[T](t: T) {
def |[U](u: => U)(implicit orFacilitator: OrAbleFacilitator[T, U]): U = {
orFacilitator(t, u)
}
}
What am I doing wrong?
I moved a bunch of little things to get things to work. I tried to comment most places I made changes to get it running.
import language.implicitConversions
import scala.util.{Try, Success, Failure}
// you need to wrap this all in an object, since you can't have vals at the top level
object Main extends App {
// you need to capture in the trait that you are abstracting of a
// * → * kind, that is to say it needs to be a type which takes a type
// as input and returns you a type, such as Option or Try or List.. The thing you are creating an
// orable for is going to have to be in the shape F[A], not just F,
// and there is no reason to fix the inner type
trait OrAbleFacilitator[F[_]] {
// the first parameter to apply needs to be F[T], and the return type must be a supertype of T
def apply[T, U >: T](t: F[T], u: => U): U
}
implicit val OptionOrAbleFacilitator = new OrAbleFacilitator[Option] {
// here we need to accept the types for the input and output, adn they must be realted
def apply[T, U >: T](t: Option[T], u: => U): U = {
t match {
case Some(v) => v
case _ => u
}
}
}
implicit val TryOrAbleFacilitator = new OrAbleFacilitator[Try] {
def apply[T, U >: T](t: Try[T], u: => U): U = {
t match {
case Success(v) => v
case _ => u
}
}
}
// we can't just wrap any old T, it has to be something in the shape
// F[T] moved the implcit up to where we create the class so that it
// doesn't cuase us to have an additional parameter list on our |
// function ( which would prevent us from using it inline )
implicit class OrAble[F[_], T](t: F[T])(implicit or: OrAbleFacilitator[F]) {
// the vertical bar | is already a keyword in scala, I used the formal "disjunction" operatior (|) instead.
def |[U >: T](u: => U): U = {
or(t, u)
}
}
// and it works:
val noneint: Option[Int] = None
val failint: Try[Int] = Failure(new Exception())
assert((Some(0) : Option[Int]) .|(Some(1)) == 0)
assert((noneint | 2) == 2)
assert(((Success(0) : Try[Int]) | 3) == 0)
assert((failint | 4) == 4)
}