aepurniet
aepurniet

Reputation: 1727

Implicit Conversion from tuple to custom type parameterized by size of tuple

I have a type X[D <: Int] that I would like to convert to implicitly from a tuple. Specifically a tuple of length D whose members are all Int should be convertable to an X[D].

I am not able to write a Conversion[A, B] to properly perform this.

Scastie playground with my attempt

https://scastie.scala-lang.org/R3BEymtWSaqTCtDTsirTKw

import scala.language.implicitConversions

// tuple types

type TupleAllAre[A] = [T <: Tuple] =>> T =:= TupleElementsAre[T, A]

type TupleElementsAre[T <: Tuple, A] <: Tuple = T match
   case A *: rest  => A *: TupleElementsAre[rest, A]
   case EmptyTuple => EmptyTuple

// tuple types work

val s1 = summon[TupleAllAre[Int][(Int, Int)]]
// Expected error
// val s2 = summon[TupleAllAre[Int][(Int, String, Int)]]

// target classes / methods

class X[D <: Int](x: Seq[Int]):
   def size: Int = x.size 

def definition[D <: Int](x: X[D]): Unit = ???

def def_with_conversion[T <: Tuple: TupleAllAre[Int]] (tuple: T) (using c: Conversion[T, X[Tuple.Size[T]]]): X[Tuple.Size[T]] = c(tuple)

class M[D <: Int]:
  def apply(x: X[D]): Unit = ???

val m1 = M[2]()

extension [T <: Tuple: TupleAllAre[Int]] (tuple: T)

  def ext(using c: Conversion[T, X[Tuple.Size[T]]]): X[Tuple.Size[T]] = c(tuple)

// conversion
given [T <: Tuple: TupleAllAre[Int]]: Conversion[T, X[Tuple.Size[T]]] = ???
// works with a non generic conversion
// given Conversion[(Int, Int), X[2]] = ???

// should all work

val x1: X[2] = (16, 16)

val d1 = definition[2](2, 2)
val d2: X[2] = def_with_conversion(2, 2)

val a1 = m1(2, 2)

val e1: X[2] = (2, 2).ext

Upvotes: 1

Views: 207

Answers (1)

Alfilercio
Alfilercio

Reputation: 1118

If what you are trying to achieve is to have a type that X[D] that represent a tuple of D elements all Integer this is a way to achieve it:

import scala.compiletime.ops.int.*

type S = Singleton & Int

type X[D <: S] = D match
  case 0 => EmptyTuple
  case _ => Int *: X[-[D, 1]]

val x: X[2] = (1,2)

def definition[D <: S](x: X[D]): Unit = ()

val x1: X[2] = (16, 16)
println(x1)

val d1 = definition[2]((2, 2))

https://scastie.scala-lang.org/alfonsorr/pk2Avg4YToKaWtKUKxinJA

Upvotes: 2

Related Questions