Я хотел бы создать эквивалент:
def toTupleN[A1, ..., AN, L <: HList](l: L): TupleN[A1, ..., AN]
Код с использованием toTupleN
должен компилироваться только тогда, когда в l
имеется ровно одна комбинация N
значений, из которой может быть создан кортеж. Все остальное должно генерировать ошибку времени компиляции. Необходимо учитывать неявные преобразования. Обратите внимание: нет ограничений на размер l
или порядок значений в нем.
Пример:
val l = 23 :: (1, "wibble") :: (2, "wobble") :: "foo" :: HNil
// l: shapeless.::[Int,shapeless.::[(Int, String),shapeless.::[(Int, String),shapeless.::[String,shapeless.HNil]]]] = 23 :: (1,wibble) :: (2,wobble) :: foo :: HNil
val t2: (String, Int) = toTuple2(l)
// t2: (String, Int) = (foo,23)
val nope: (String, String) = toTuple2(l)
// Compiler error because no combination of l values can create nope
val nein: ((Int, String)) = toTuple2(l)
// Another compiler error because there is more than one way l values can create nein
Этот вопрос возник из ответа на следующий question. Более общий механизм в этом вопросе может быть использован как для создания структур данных, так и для вызова любой стандартной функции (аргументы которой имеют разные типы) с помощью FunctionN#tupled
.
Update:
Некоторые примеры для определения желаемого поведения с подтипами:
trait A
trait B extends A
trait C extends A
val a: A
val b: B
val c: C
toTuple2[(A, Int)](5 :: b :: HNil) // (b, 5): subtypes match supertypes when there is no exact match
toTuple2[(A, Int)](5 :: b :: a :: HNil) // (a, 5): only one exact match is available
toTuple2[(A, Int)](5 :: a :: a :: HNil) // compile error: more than one exact match is available
toTuple2[(A, Int)](5 :: b :: c :: HNil) // compile error: more than one inexact match is available