简体   繁体   English

为什么scala不推断继承特征的类型成员?

[英]Why doesn't scala infer the type members of an inherited trait?

I have a group of types that each have their own type member: 我有一组类型,每个类型都有自己的类型成员:

sealed trait FieldType {
    type Data
    def parse(in: String): Option[Data]
}
object Name extends FieldType { 
    type Data = String 
    def parse(in: String) = Some(in)
}
object Age extends FieldType { 
    type Data = Int 
    def parse(in: String) = try { Some(in.toInt) } catch { case _ => None }
}

And I have a group of types that operate on sets of the FieldType s (using boilerplate rather than abstracting over arity): 我有一组类型可以在FieldType的集合上运行(使用样板而不是抽象的arity):

sealed trait Schema {
    type Schema <: Product
    type Data <: Product
    val schema: Schema
    def read(in: Seq[String]): Option[Data]
}
trait Schema1 extends Schema {
    type D1
    type FT1 <: FieldType { type Data = D1 }
    type Schema = Tuple1[FT1]
    type Data = Tuple1[D1]
    def read(in: Seq[String]) = schema._1.parse(in(0)).map(Tuple1.apply)
}
trait Schema2 extends Schema {
    type D1
    type D2
    type FT1 <: FieldType { type Data = D1 }
    type FT2 <: FieldType { type Data = D2 }
    type Schema = (FT1, FT2)
    type Data = (D1, D2)
    def read(in: Seq[String]) = {
        for {
            f <- schema._1.parse(in(0))
            s <- schema._2.parse(in(1))
        } yield (f, s)
    }
}

I thought I could use this system to elegantly define sets of fields that are meaningful because scala would be able to infer the type members: 我以为我可以使用这个系统来优雅地定义有意义的字段集,因为scala能够推断出类型成员:

class Person extends Schema2 {
    val schema = (Name, Age)
}

However, this doesn't compile! 但是,这不编译! I have to include definitions for all the type members: 我必须包含所有类型成员的定义:

class Person extends Schema2 {
    type D1 = String; type D2 = Int
    type FT1 = Name.type; type FT2 = Age.type
    val schema = (Name, Age)
}

How come scala can't infer D1,... and FT1,...? scala怎么不能推断D1,...和FT1,...? How can I refactor this so I don't have to specify the type variables in Person ? 我怎样才能重构这个,所以我不必在Person指定类型变量?

Note: Once I have a better understanding of macros, I plan to use them for the Schema types. 注意:一旦我对宏有了更好的理解,我计划将它们用于Schema类型。 Also, I'd rather not use shapeless. 而且,我宁愿不使用无形。 It's a great library, but I don't want to pull it in to solve this one problem. 这是一个很棒的图书馆,但我不想把它拉进来解决这个问题。

By declaring this: 通过声明:

val schema: Schema

you specify that schema must of type Schema or any of its subtypes . 您指定该schema必须是Schema类型或其任何子类型 Hence, knowing the type of schema , you cannot infer Schema because it could be any supertype of schema.type . 因此,了解schema的类型,您无法推断Schema因为它可能是schema.type任何超类型

You can solve your problem by reversing completely the thing: define the type alias in terms of schema.type : 您可以通过完全颠倒事物来解决您的问题:根据schema.type定义类型别名:

trait Schema2 extends Schema {
    type Schema = (FieldType, FieldType)
    type FT1 = schema._1.type
    type FT2 = schema._2.type
    type D1 = FT1#Data
    type D2 = FT2#Data
    type Data = (D1, D2)
    def read(in: Seq[String]) = {
        for {
            f <- schema._1.parse(in(0))
            s <- schema._2.parse(in(1))
        } yield (f, s)
    }
}

(Not sure it will actually work, but in theory this should typecheck.) (不确定它是否真的有效,但理论上这应该是检查。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM