Странное влияние неявного Mapper на неявный параметр Mapped
Предположим, у меня есть контейнер-маркер
case class TypedString[T](value: String)
и частичная функция трюк
abstract class PartFunc[Actual <: HList] {
val poly: Poly
def apply[L1 <: HList](l: L1)(implicit
mapped: Mapped.Aux[Actual, TypedString, L1],
mapper: Mapper[poly.type, L1]): L1 = l
}
Поли для Mapper
object f extends (TypedString ~>> String) {
def apply[T](s : TypedString[T]) = s.value
}
и метод результата
def func[Actual <: HList] = new PartFunc[Actual] {
val poly = f
}
Пример использования:
func[
Int :: String :: HNil
](TypedString[Int]("42") :: TypedString[String]("hello") :: HNil)
Этот код не выполняется во время компиляции, потому что компилятор не может найти Mapped
неявный параметр:
could not find implicit value for parameter mapped:
shapeless.ops.hlist.Mapped[shapeless.::[Int,shapeless.::[String,shapeless.HNil]],nottogether.MapperTest.TypedString]{type Out = shapeless.::[nottogether.MapperTest.TypedString[Int],shapeless.::[nottogether.MapperTest.TypedString[String],shapeless.HNil]]}
](TypedString[Int]("42") :: TypedString[String]("hello") :: HNil)
Но если мы удалим Mapper
неявный параметр из PartFunc.apply(...)
подпись все отлично работает. Поэтому я понятия не имею, почему и как Mapper
влияние на Mapped
,
1 ответ
Компилятор жалуется на Mapped
в то время как фактическая проблема с Mapper
, Я не уверен, почему, но, похоже, что-то не так с получением Mapped
для одиночного типа poly.type
когда poly
является абстрактным значением или аргументом конструктора PartFunc
,
Решение было бы сделать poly
P <: Poly
и передавая тип синглтон вместе с Actual
когда мы создаем PartFunc
:
import shapeless._
import ops.hlist.{Mapped, Mapper}
import poly.~>>
abstract class PartFunc[Actual <: HList, P <: Poly] {
val poly: P
def apply[L1 <: HList](l: L1)(implicit
mapped: Mapped.Aux[Actual, TypedString, L1],
mapper: Mapper[P, L1]
): mapper.Out = mapper(l)
}
def func[Actual <: HList] = new PartFunc[Actual, f.type] { val poly = f }
Или с обычным классом:
class PartFunc[Actual <: HList, P <: Poly](poly: P) {
def apply[L1 <: HList](l: L1)(implicit
mapped: Mapped.Aux[Actual, TypedString, L1],
mapper: Mapper[P, L1]
): mapper.Out = mapper(l)
}
def func[Actual <: HList] = new PartFunc[Actual, f.type](f)
Обратите внимание, что теперь мы должны написать mapper(l)
, так как l map poly
все равно будет искать Mapped[poly.type, L1]
,
Теперь мы можем позвонить func
:
func[
Int :: String :: HNil
](TypedString[Int]("42") :: TypedString[String]("hello") :: HNil)
// String :: String :: HNil = 42 :: hello :: HNil
Я уверен, что кто-то, обладающий более глубокими знаниями о системе типов Scala, сможет дать нам более четкое объяснение и, возможно, лучшее решение этой проблемы.