dotty-feature-requests icon indicating copy to clipboard operation
dotty-feature-requests copied to clipboard

Tuple.IsMappedBy should provide inductive instances

Open mpilquist opened this issue 5 years ago • 4 comments

minimized code

def isMappedByShouldBeInductive1[F[_], A, B <: Tuple](using ev: Tuple.IsMappedBy[F][A *: B]) =
  summon[Tuple.IsMappedBy[F][B]]

def isMappedByShouldBeInductive2[F[_], A <: Tuple](using ev: Tuple.IsMappedBy[F][A]) =
  summon[Tuple.IsMappedBy[F][Tuple.Tail[A]]]

Compilation output

scala> def isMappedByShouldBeInductive1[F[_], A, B <: Tuple](using ev: Tuple.IsMappedBy[F][A *: B]) = summon[Tuple.IsMappedBy[F][B]]
1 |def isMappedByShouldBeInductive1[F[_], A, B <: Tuple](using ev: Tuple.IsMappedBy[F][A *: B]) = summon[Tuple.IsMappedBy[F][B]]
  |                                                                                                                             ^
  |no implicit argument of type Tuple.IsMappedBy[F][B] was found for parameter x of method summon in object DottyPredef.
  |I found:
  |
  |    <:<.refl[Nothing]
  |
  |But method refl in object <:< does not match type Tuple.IsMappedBy[F][B].

scala> def isMappedByShouldBeInductive2[F[_], A <: Tuple](using ev: Tuple.IsMappedBy[F][A]) = summon[Tuple.IsMappedBy[F][Tuple.Tail[A]]]
1 |def isMappedByShouldBeInductive2[F[_], A <: Tuple](using ev: Tuple.IsMappedBy[F][A]) = summon[Tuple.IsMappedBy[F][Tuple.Tail[A]]]
  |                                                                                                                                 ^
  |no implicit argument of type Tuple.IsMappedBy[F][Tuple.Tail[A]] was found for parameter x of method summon in object DottyPredef.
  |I found:
  |
  |    <:<.refl[Nothing]
  |
  |But method refl in object <:< does not match type Tuple.IsMappedBy[F][Tuple.Tail[A]].

mpilquist avatar Feb 15 '20 17:02 mpilquist

Workaround

given a[F[_], Head, Tail <: Tuple](using Tuple.IsMappedBy[F][Head *: Tail]) as Tuple.IsMappedBy[F][Tail] = Predef.$conforms.asInstanceOf
given b[F[_], T <: NonEmptyTuple](using Tuple.IsMappedBy[F][T]) as Tuple.IsMappedBy[F][Tuple.Tail[T]] = Predef.$conforms.asInstanceOf

def isMappedByShouldBeInductive1[F[_], A, B <: Tuple](using ev: Tuple.IsMappedBy[F][A *: B]) =
  summon[Tuple.IsMappedBy[F][B]]

def isMappedByShouldBeInductive2[F[_], A <: NonEmptyTuple](using ev: Tuple.IsMappedBy[F][A]) =
  summon[Tuple.IsMappedBy[F][Tuple.Tail[A]]]

nicolasstucki avatar Feb 17 '20 10:02 nicolasstucki

Conversly

given c[F[_], Elem, T <: Tuple](using Tuple.IsMappedBy[F][T]) as Tuple.IsMappedBy[F][F[Elem] *: T] = Predef.$conforms.asInstanceOf

nicolasstucki avatar Feb 17 '20 10:02 nicolasstucki

b works for both cases but does not get infered in the first case

def isMappedByShouldBeInductive1[F[_], A, B <: Tuple](using ev: Tuple.IsMappedBy[F][A *: B]) =
  summon[Tuple.IsMappedBy[F][B]]//(using b)

given b[F[_], T <: NonEmptyTuple](using Tuple.IsMappedBy[F][T]) as Tuple.IsMappedBy[F][Tuple.Tail[T]] = Predef.$conforms.asInstanceOf

nicolasstucki avatar Feb 17 '20 11:02 nicolasstucki

In case it's interesting, I was using this in scodec to implement Codec.fromTuple -- I ended up casting instead of relying on the inductive instances.

https://github.com/scodec/scodec/blob/50ca6194d8bbb571b7ba956cbe3c19ae242b0128/shared/src/main/scala/scodec/Codec.scala#L628-L637

mpilquist avatar Feb 17 '20 13:02 mpilquist