2016-10-02 3 views
4

Я пытался сопоставить типы HList с пакетом shapeless от scala, не имея доступа к их значениям.Отобразить типы бесформенных HList

Следующая преуспевает в отображении значений из HList

import shapeless._ 
import shapeless.Poly._ 
import ops.hlist.Mapper 
import ops.hlist.Mapper._ 

trait Person { 
    type Value 
    val v : Value 
} 

case class StringPerson extends Person { 
    type Value = String 
    val v = "I like strings" 
} 

case class IntPerson extends Person { 
    type Value = Int 
    val v = 42 
} 

object what_is_going_on { 

    object test_value_op { 
    val stringPerson = StringPerson() 
    val intPerson = IntPerson() 

    trait lpvfun extends Poly1 { 
     implicit def default[A <: Person] = at[A](_.v) 
    } 

    object vfun extends lpvfun {} 

    // Use these to generate compiler errors if the mapped type is not what we'd expect: 

    type TestListType = StringPerson :: IntPerson :: HNil 
    type TestListExpectedMappedType = String :: Int :: HNil 

    // Input: 
    val testList : TestListType = stringPerson :: intPerson :: HNil 

    // Output: 
    val mappedList : TestListExpectedMappedType = testList map vfun 

    // Get the actual mapped type 
    type TestListActualMappedType = mappedList.type 

    // This compiles...... 
    val mappedList1 : TestListActualMappedType = mappedList 

    // .... but weirdly this line doesn't. That isn't the point of this question, but I'd be very grateful for an answer. 
    //implicitly[TestListActualMappedType =:= TestListExpectedMappedType] 
    } 

} 

Классный! Помимо того, что не удалось использовать implicitly[A =:= B], по какой-либо причине значения HList были сопоставлены и имеют свои типы.

Теперь предположим, что у нас нет значения HList, но мы знаем его тип. Как мы можем сопоставить его типы?

Я попытался следующие основанный на определении maphere:

object test_type_op { 
    type TestListType = StringPerson :: IntPerson :: HNil 
    type TestListExpectedMappedType = String :: Int :: HNil 

    // Attempt 1 does not work, compiler cannot prove =:= 
    type MappedType = Mapper[vfun.type, TestListType]#Out 
    implicitly[MappedType =:= TestListExpectedMappedType] 

    // Attempt 2 does not work, compiler cannot prove =:= 
    class GetMapper { 
    implicit val mapper : Mapper[vfun.type, TestListType] 
    implicitly[mapper.Out =:= TestListExpectedMappedType] 
    } 

} 

Как один получить тип отображенного HList, не имея доступа к его стоимости? Есть ли способ отладки, почему компилятор не может что-то доказать? Спасибо за чтение.

ответ

2

В случае TestListActualMappedType у вас есть одноэлементный тип для mappedList, который не совпадает с выведенным типом mappedList. Вы можете увидеть точно такую ​​же проблему без привлечения бесформенные:

scala> val x = "foo" 
x: String = foo 

scala> implicitly[x.type =:= String] 
<console>:13: error: Cannot prove that x.type =:= String. 
     implicitly[x.type =:= String] 
       ^

Вы можете попросить доказательства того, что x.type является подтипом String или вы могли бы использовать shapeless.test.typed, который будет выглядеть, как это в вашем случае:

import shapeless._, ops.hlist.Mapper 

trait Person { 
    type Value 
    val v : Value 
} 

case class StringPerson() extends Person { 
    type Value = String 
    val v = "I like strings" 
} 

case class IntPerson() extends Person { 
    type Value = Int 
    val v = 42 
} 

trait lpvfun extends Poly1 { 
    implicit def default[A <: Person] = at[A](_.v) 
} 

object vfun extends lpvfun {} 

val stringPerson = StringPerson() 
val intPerson = IntPerson() 

val testList = stringPerson :: intPerson :: HNil 
val mappedList = testList map vfun 

shapeless.test.typed[String :: Int :: HNil](mappedList) 

Это действительно не покупает вас, явно указывая тип.

Вы можете попросить доказательства того, что выходной типа класса типа, как Mapper типа вы ожидаете для конкретных типов ввода:

scala> val m = Mapper[vfun.type, StringPerson :: IntPerson :: HNil] 
m: shapeless.ops.hlist.Mapper[vfun.type,shapeless.::[StringPerson,shapeless.::[IntPerson,shapeless.HNil]]]{type Out = shapeless.::[String,shapeless.::[Int,shapeless.HNil]]} = [email protected] 

scala> implicitly[m.Out =:= (String :: Int :: HNil)] 
res1: =:=[m.Out,shapeless.::[String,shapeless.::[Int,shapeless.HNil]]] = <function1> 

Это более вероятно, будет полезно, но опять же это зависит от того, что именно вы пытаетесь убедить себя.

+0

Thankyou - это действительно помогает. Во втором блоке кода, что происходит с 'm' во время компиляции? Оптимизирован ли он? Есть ли способ получить тип, который 'm.Out' имел бы без фактического создания каких-либо значений? – user1158559

Смежные вопросы