2016-07-29 6 views
1

У меня есть следующий код в основном перебирать полей case class и сопоставить их с помощью Poly к тому же типу и использовать ToList[HL, Out]Shapeless: Как выразить <: случай типа класса пары для Generix.Aux

для простоты мы можем предположить Poly делает это:

object Schema extends Poly1 { 
    implicit def caseInt = at[Int](_ => "I'm an int") 
    implicit def caseString = at[String](_ => "Oh boy a string") 
} 

def infer[V1 <: Product, Out <: HList, MapperOut <: HList](v1: V1)(
    implicit gen: Generic.Aux[V1, Out], 
    map: Mapper.Aux[Schema.type, Out, MapperOut], 
    to: ToList[MapperOut, String] 
): List[String] = to (gen to v1 map Schema) 

Это все очень просто и работает очень хорошо для простых сценариев:

case class Test(id: Int, text: String) 
val list = infer(Test(2, "text")) 
// List("I'm an int", "Oh boy a string") 

Теперь выходить туда, где автобусы не работают:

class Automagical[T <: Product with Serializable : TypeTag] { 
    def instance: T 
    // The typetag bit is needed for something else 
    def convert: List[String] = infer(instance) 
} 

К сожалению, любой вызов выше терпит неудачу с:

could not find implicit value for parameter gen: shapeless.Generic.Aux[T,Out] 

Bonus

Как я могу улучшить метод infer не требуя экземпляра T? Очевидно, что вывод типа прекрасен, но мне нужно как-то материализовать List[String] с HList[Lub] и переложить что-то на что-то.

Учитывая я только когда-либо заботиться о типах, можно вывести конкретный экземпляр List[String] лишь зная типы быть поли отображенных кодируются как HList?

Что-то вроде:

def infer[V1 <: Product, Out <: HList, MapperOut <: HList]()(
    implicit gen: Generic.Aux[V1, Out], 
    map: Mapper.Aux[Schema.type, Out, MapperOut], 
    to: ToList[MapperOut, String] 
): List[String] = { 
    // Magically build an HList with samples from its types. 
    // Or an alternative approach that gives the same outcome 
    val reifiedInstance = reify[Out] 
    to (reifiedInstance map Schema) 
} 
+0

Функция Automagical не компилируется для меня: «У черт нет параметров типа с границами контекста», но, конечно, указанная вами ошибка встречается и с абстрактным классом. – devkat

+0

@devat Моя ошибка, это был класс в оригинальной реализации. – flavian

ответ

1

Чтобы гарантировать, что convert имеет доступ к неявным параметрам для infer, они должны присутствовать при создании экземпляра Automagical:

abstract class Automagical[T <: Product with Serializable : TypeTag, 
    Out <: HList, MapperOut <: HList] 
    (implicit 
    gen: Generic.Aux[T, Out], 
    map: Mapper.Aux[Schema.type, Out, MapperOut], 
    to: ToList[MapperOut, String]) { 
    def instance: T 
    // The typetag bit is needed for something else 
    def convert: List[String] = infer(instance) 
} 
+0

Это сделало бы это не в моем случае, так как мне нужно, чтобы Automagical был стильным классом. – flavian

+0

Я принял ответ, поскольку он решает эту конкретную проблему. Есть ли способ справиться с тем, что вам не нужна вещь, о которой вы знаете? – flavian

+0

scalacheck-shapeless (https://github.com/alexarchambault/scalacheck-shapeless) может создавать примеры экземпляров для классов case, возможно, через 'HLists'. Возможно, стоит проверить, как это делается. – devkat