Why Does This Type Constraint Fail for List[Seq[AnyVal or String]]
Asked Answered
I

1

1

I am learning about Scala on my own and ran into this. Following on from the excellent answers at Link, suppose I have the following code:

object Example extends App {
  val x = Seq(1, 2, 3)
  val y = Seq("1", "2", "3")

  class Or[A, B]
  implicit def orA[A, B](implicit ev: A): Or[A, B] = new Or
  implicit def orB[A, B](implicit ev: B): Or[A, B] = new Or

  def f1[T](seq: Seq[T])(implicit ev: Or[T =:= Int, T =:= String]) = {
    println(seq)
  }

  f1(Seq(1, 2, 3))
  f1(Seq("1", "2", "3"))
}

This compiles all well and good. But now lets suppose I change the function so that it takes a List of Sequences, instead of just Sequences, and try the following:

object Example extends App {
  val x = Seq(1, 2, 3)
  val y = Seq("1", "2", "3")

  class Or[A, B]
  implicit def orA[A, B](implicit ev: A): Or[A, B] = new Or
  implicit def orB[A, B](implicit ev: B): Or[A, B] = new Or

  def f1[T](seq: List[Seq[T]])(implicit ev: Or[T =:= Int, T =:= String]) = {
    println(seq)
  }

   f1(List(Seq(1, 2, 3), Seq("1", "2", "3")))
}

This however fails. The error message is:

could not find implicit value for parameter ev: conusviz.Example.Or[Any =:= Int,Any =:= String]

My question is, why is this happening? I simply wrapped something the compiler should be able to infer in another type. Is there a way to get this working?

I want to the function to take a List of Int (or Indeed AnyVal) or Strings and still work. I am just a little baffled as to why the compiler is confused. Any explanation along a coded answer would be deeply appreciated from a learning perspective.

Impudicity answered 13/6, 2020 at 21:28 Comment(2)
You can not mix types. You now have a List[Seq[Any]]], for which you do not have support.Bettencourt
Thank you. I see, so just to aid my understanding, there is no way to tell the compiler I only will pass this function a Seq[Int] OR a Seq[String] inside the list?Impudicity
F
5

Seq(1, 2, 3) has type Seq[Int], Seq("1", "2", "3") has type Seq[String]. Both Seq[Int] and Seq[String] are subtypes of Seq[Any]. So List(Seq(1, 2, 3), Seq("1", "2", "3")) has type List[Seq[Any]].

If you want types Seq[Int] and Seq[String] to be preserved then you need not a List but HList

import shapeless.{HList, HNil}
import shapeless.ops.hlist.LiftAll

def f[L <: HList](seq: L)(implicit ev: LiftAll[({type l[T] = Or[T =:= Seq[Int], T =:= Seq[String]]})#l, L]) = {
  println(seq)
}

f(Seq(1, 2, 3) :: Seq("1", "2", "3") :: HNil)
Frenchy answered 13/6, 2020 at 21:45 Comment(3)
That's a great answer, now I will spend many hours trying to get my head round this shapeless library. Thanks!Impudicity
@Impudicity My personal advice is that you are diving too much into very advanced topics.Bettencourt
Thanks @LuisMiguelMejíaSuárez, I must say Scala does seem very complex compared to languages I have learnt before. I guess I will try and find a basic book and go a bit slower on the theory as I don't have a good foundation in types yet. Thanks for all the guidanceImpudicity

© 2022 - 2024 — McMap. All rights reserved.