ToList on a formless HList fails when the resulting existential type is too complex

Given the following definitions:

class R[T] class A class B class C 

It works:

 val s1 = new R[A] :: new R[B] :: HNil val r1 = s1.toList // r1 of type: List[R[_ >: A with B]] 

So far this is not the case:

 val s2 = new R[A] :: new R[B] :: new R[C] :: HNil val r2 = s2.toList // could not find implicit value for parameter toList: // shapeless.ToList[shapeless.::[R[A], // shapeless.::[R[B],shapeless.::[R[C],shapeless.HNil]]],Lub] 

Where i expect:

 // r2 of type: List[R[_ >: A with B with C]] 

Pseudo-solution:

Set yourself:

 val r3 = s2.toList(ToList.hlistToList[R[A], R[B], ::[R[C], HNil], R[_ >: A with B with C]]) 

This, of course, is not a solution, because it eliminates all the advantages of HLists ( HList provided by the caller along with all the necessary implications).

Explanation

I am glad if I get List[R[_]] at the end without type restrictions.

+4
source share
2 answers

The code you wrote should just work as it is, creating the exact existential type you expected. It would be very helpful if you open a bug against formlessness so that the fix for this is not forgotten for the next version.

At the same time, if the type you are really using is List[R[_]] (which is most likely to be useful to me), you can request it clearly much easier than your workaround,

 scala> import shapeless._ import shapeless._ scala> class R[T] ; class A ; class B ; class C defined class R defined class A defined class B defined class C scala> val s2 = new R[A] :: new R[B] :: new R[C] :: HNil s2: R[A] :: R[B] :: R[C] :: HNil = R@7a26bc5e :: R@518fdf9 :: R@2bc9e90c :: HNil scala> s2.toList[R[_]] res0: List[R[_]] = List( R@7a26bc5e , R@518fdf9 , R@2bc9e90c ) 

Given that this less accurate type is likely to be more useful in context, you will want to continue using the explicit element type argument until toList even after fixing the error, so I believe this is the correct answer and not a workaround.

+4
source

I just passed a PR that fixes this.

Just calling s2.toList without explicitly specifying a type should return the same type as if you created a (standard) list with the same elements and let scalac infer the type of the list for you (it's something like List[R[_ >: A with B with C]] ).

0
source

Source: https://habr.com/ru/post/1482282/


All Articles