2016-06-30 7 views
2

Предположим, что у меня есть контейнер-маркерстранно влияние неявной 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.

ответ

3

Компилятор жалуется на Mapped, в то время как фактическая проблема связана с Mapper. Я не уверен, почему, но, похоже, что-то случилось с получением Mapped для одноэлементного типа poly.type, когда poly - это абстрактное значение или аргумент конструктора PartFunc.

Решение было бы сделать polyP <: 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 может предоставить нам более ясным объяснением и, возможно, лучшим решением для этой проблемы.

+0

Я задал этот вопрос в бесформенной комнате без ответа. Спасибо за Вашу поддержку. Какую книгу или статьи вы предлагаете прочитать, чтобы быть более знакомыми с типами scala? –