FnToProduct не работает с конструктором типов

#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) }
  

Это немного дополнительный синтаксический шум, но он работает.