Scala 2 では、Shapeless を使用して、これを行うことができます ( Scastie ):
def f[T <: Product, H <: HList](tupleOfFoos: T)(
implicit gen: Generic.Aux[T, H],
hev: LiftAll[({type E[T] = Foo =:= T})#E, H]
) = tupleOfFoos
LiftAll
Foo =:= X
for every X
inのインスタンスがあることを確認し、H
とが完全に無関係な型ではないことを確認します。gen
T
H
Dotty では、このための一致タイプを持つ証拠パラメーターを追加できます。
type Homogenous[H, T <: Tuple] = T match {
case EmptyTuple => DummyImplicit
case H *: t => Homogenous[H, t]
case _ => Nothing
}
def f[T <: Tuple](tupleOfFoos: T)(using Homogenous[Foo, T]) = tupleOfFoos
これにより、呼び出すことはできますf((Foo(), Foo(), Foo()))
が、f((1, 2, 3))
.
Homogenous
は、ベース ケースが の再帰マッチ タイプですEmptyTuple
。タプルが空の場合、それは非Foo
s で埋められないため、型は になりDummyImplicit
、暗黙的にスコープ内に既にあります。(H, ...)
それ以外の場合は、 /のように見えるかどうかを確認します。H *: t
その場合、残りのタプル ( t
) も有効かどうかを確認する必要があります。その 2 番目のケースに一致しない場合、タプルが無効であることがわかります。この場合、結果はNothing
になります。正気な人は暗黙の値を作成しません。
コンテキスト境界を使用する場合は、追加のカリー化された型 ( Scastie )を作成できます。
type Homo2[H] = [T <: Tuple] =>> Homogenous[H, T]
def f[T <: Tuple : Homo2[Foo]](tupleOfFoos: T) = tupleOfFoos
残念ながら、単一のカリー化された型 ( Scastie )で動作させることができませんでした。
type Homogenous[H] = [T <: Tuple] =>> T match {
case EmptyTuple => DummyImplicit
case H *: t => Homogenous[H][t]
case _ => Nothing
}