#scala #shapeless #type-constructor
#scala #бесформенный #тип-конструктор
Вопрос:
Почему это работает так, как ожидалось:
def method1[L <: HList, M <: HList, F, R](list: L)(builder: F)
(implicit ev: Comapped.Aux[L, Seq, M],
fntp: FnToProduct.Aux[F, M => R]) = println("asd")
method1(Seq("asd") :: HNil) { (s: String) =>
6
}
Но это не так?
def method2[L <: HList, M <: HList, F, R](list: L)(builder: F)
(implicit ev: Comapped.Aux[L, Seq, M],
fntp: FnToProduct.Aux[F, M => Seq[R]]) = println("asd")
method2(Seq("asd") :: HNil) { (s: String) =>
Seq(6)
}
Кажется, что добавление конструктора типа в возвращаемый тип для FnToProduct .Aux нарушает его.
Ответ №1:
Проблема в том, что когда компилятор пытается вывести параметры типа для method1
, он L
без проблем найдет и M
и F
, но затем, когда он доберется до R
, он не сможет определить, что второй параметр FnToProduct.Aux
имеет правильную форму для выравнивания M => Seq[R]
.
У меня нет хорошего объяснения, почему это происходит во втором случае, а не в первом, но это ограничение, с которым вы столкнетесь довольно часто, и есть пара обходных путей.
Первым было бы Aux
полностью оставить FnToProduct
выключение. В зависимости от того, что делает ваш фактический метод, это может быть просто замечательно, но если вам нужно R
явно ссылаться на, это не сработает.
Вторым обходным путем было бы позволить вывести возвращаемый тип этого параметра второго типа, а затем запросить доказательства того, что это Seq
:
import shapeless._, ops.function.FnToProduct, ops.hlist.Comapped
def method2[L <: HList, M <: HList, F, S, R](list: L)(builder: F)
(implicit
ev: Comapped.Aux[L, Seq, M],
fntp: FnToProduct.Aux[F, M => S],
s: S <:< Seq[R]
) = println("asd")
method2(Seq("asd") :: HNil) { (s: String) => Seq(6) }
Это немного дополнительный синтаксический шум, но он работает.