部分应用类型参数和typetag的写入方法难度大

时间:2013-05-04 18:44:57

标签: scala type-parameter partially-applied-type

我正在寻找一种方法,可以在以下示例中从S的调用中删除类型参数apply

object Attribute {
  trait Int    [S] extends Attribute[S]
  trait Boolean[S] extends Attribute[S]  // etc.
}
sealed trait Attribute[S]

trait Attributes[S] {
  protected def get(key: String): Option[Attribute[S]]

  def apply[A <: Attribute[S]](key: String)
                              (implicit tag: reflect.ClassTag[A]): Option[A] = 
    get(key) match {
      case Some(attr: A) => Some(attr)
      case _             => None
    }
}

根据上述定义,测试用例将是:

trait Test[S] {
  def map: Attributes[S]

  map[Attribute.Int[S]]("foo")
}

我正在尝试做的是修改apply定义以允许以下内容:

trait Test2[S] {
  def map: Attributes[S]

  map[Attribute.Int]("foo")   // use partially applied attribute type
}

编辑:所以跟进Marius的建议和评论,为什么以下仍然会产生删除警告:

import reflect.runtime.universe._

trait Attributes[S] {
  protected def get(key: String): Option[Attribute[S]]

  def apply[A[x] <: Attribute[x]](key: String)
                                 (implicit tag: TypeTag[A[S]]): Option[A[S]] =
    get(key) match {
      case Some(attr: A[S]) => Some(attr)
      case _                => None
    }
}

对我来说显然没有意义。一方面,我有A[S]的完整类型标签。另一方面,它应该在缺席时完全工作,因为AttributeS是不变的,所以如果我得到Option[Attribute[S]],我与Some(attr: A[x])匹配,唯一的可能是x == S


编辑2 :解决方案的条件是Attribute特征的形状不会改变,例如不将类型构造函数参数S移动到成员字段。

4 个答案:

答案 0 :(得分:3)

您是否考虑过利用隐含unapply的{​​{1}}?如果我正确理解文档,如果ClassTag与其类型不完全匹配,则标记中的unapply将返回“无”。如果匹配,则会返回某些类型attr。所以重构使用unapply,你的代码看起来像这样:

A[S]

答案 1 :(得分:1)

我认为你想要更高级的类型。我重写了你的代码:

trait Attributes[S] {
  protected def get(key: String): Option[Attribute[S]]

  def apply[A[_] <: Attribute[_]](key: String)
                              (implicit tag: reflect.ClassTag[A[S]]): Option[A[S]] =
    get(key) match {
      case Some(attr: A[S]) => Some(attr)
      case _             => None
    }
}

请注意,现在A类型参数是更高阶的类型。因此,在apply方法中的每次出现时,您都需要将A“应用”到另一种类型以获得正确的类型。

此问题为更高阶类型提供了更多见解:

What is a higher kinded type in Scala?

答案 2 :(得分:1)

一种方式。请注意,调用任何类型的Int,即使是嵌套的Int也需要一定的chutzpah。

import scala.reflect._

sealed trait Attribute {
  type S
}

object Attribute {
  trait Ints extends Attribute { type S = Int }
}

/** A container for attributes of a certain type.
 */
trait Attributes[E] {
  type Attr = Attribute { type S <: E }
  protected def get(key: String): Option[Attr]

  /** Retrieve the value for the given key.
   *  @tparam A must be our notion of Attribute
   *  @return optionally the A you asked for
   */
  def apply[A <: Attr](key: String)(implicit tag: ClassTag[A]): Option[A] =
    get(key) match {
      case Some(attr: A) => Some(attr)
      case _             => None
    }
}
trait Test2 {
  /** Map keys to ints. */
  def map: Attributes[Int]

  /** Retrieve a value. */
  map[Attribute.Ints]("foo")   // use partially applied attribute type
}

答案 3 :(得分:0)

这只是为了表明@cmbaxter的答案按预期工作。我还将重述初始代码,以便它完全可执行:

// 属性界面

object Attribute {
  trait Int    [S] extends Attribute[S]
  trait Boolean[S] extends Attribute[S]  // etc.
}
sealed trait Attribute[S]

// 属性地图界面

trait Attributes[S] {
  protected def get(key: String): Option[Attribute[S]]

  def apply[A[_] <: Attribute[_]](key: String)
    (implicit tag: reflect.ClassTag[A[S]]): Option[A[S]] =
    get(key) match {
      case Some(attr) => tag.unapply(attr)
      case _          => None
    }  
  }
}

// 测试用例

class Test {
  val map = new Attributes[Foo] {
    def get(key: String) = key match {
      case "foo" => Some(new Attribute.Int    [Foo] { override def toString = "I" })
      case "bar" => Some(new Attribute.Boolean[Foo] { override def toString = "B" })
      case _     => None
    }
  }

  println(s"An int attr named `foo`: ${map[Attribute.Int    ]("foo")}")
  println(s"A bool attr named `foo`: ${map[Attribute.Boolean]("foo")}")
  println(s"An int attr named `bar`: ${map[Attribute.Int    ]("bar")}")
  println(s"A bool attr named `bar`: ${map[Attribute.Boolean]("bar")}")
  println(s"An int attr named `???`: ${map[Attribute.Int    ]("???")}")
  println(s"A bool attr named `???`: ${map[Attribute.Boolean]("???")}")
}

// 正在运行

new Test

An int attr named `foo`: Some(I)
A bool attr named `foo`: None
An int attr named `bar`: None
A bool attr named `bar`: Some(B)
An int attr named `???`: None
A bool attr named `???`: None