2010-10-11 3 views
4
sealed abstract trait HList 

case class :+:[H, T <: HList](head: H, tail: T) extends HList { 
    def :+:[T](v: T) = new :+:(v, this) 
} 

case object HNil extends HList { 
    def :+:[T](v: T) = new :+:(v, this) 
} 

object HListExpt { 
    def main(args: Array[String]) { 
    val me: String :+: Int :+: Symbol :+: HNil.type = "Rahul" :+: 20 :+: 'Male :+: HNil 
    println(me.head, me.tail.head) 
    } 
} 

На попытке скомпилировать код выше, я получаю следующее сообщение об ошибке компилятора:Как правильно ввести-аннотировать этот HList?

error: type mismatch; 
found : :+:[java.lang.String,:+:[Int,:+:[Symbol,object HNil]]] 
required: :+:[String,:+:[Int,:+:[Symbol,HNil.type]]] 
val me: String :+: Int :+: Symbol :+: HNil.type = "Rahul" :+: 20 :+: 'Male :+: HNil 

Что я здесь делаю неправильно? Каким будет правильный тип ввода-аннотации выше HList?

PS: Код компилируется отлично, когда я удаляю аннотацию типа.

ответ

7

Корневая проблема здесь состоит в том, что одноэлементные типы никогда не случайны. Вот демонстрация:

scala> case object A  
defined module A 

scala> A     
res6: A.type = A 

scala> identity[A.type](A) 
res7: A.type = A 

scala> identity(A)   
res8: object A = A 

Почему это? Quoth Odersky et. и др. Программирование в Scala, §27.6:

Usually [singleton] types are too specific to be useful, which is why the compiler is reluctant to insert them automatically.

Итак, давайте явно предоставить аргумент типа:

sealed abstract trait HList 

case class :+:[H, T <: HList](head: H, tail: T) extends HList { 
    def :+:[T](v: T) = new :+:(v, this) 
} 

case object HNil extends HList { 
    def :+:[T](v: T) = new :+:[T, HNil.type](v, this) 
} 

val me: String :+: Int :+: Symbol :+: HNil.type = "Rahul" :+: 20 :+: 'Male :+: HNil 
println(me.head, me.tail.head) 

Bonus Ссылка:

2

Я не знаю, почему, но если HNil определяется как класс все компилирует:

class HNilClass extends HList { 
    def :+:[T](v: T) = new :+:(v, this) 
} 

object HNil extends HNilClass