Scala 部分应用类型参数和类型标记的难写方法

Scala 部分应用类型参数和类型标记的难写方法,scala,type-parameter,partially-applied-type,Scala,Type Parameter,Partially Applied Type,在下面的示例中,我正在寻找从调用apply中删除类型参数S的方法: 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]]

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

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
    }
}
我试图做的是修改
apply
definition
,以允许以下内容:

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

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

编辑:那么继马吕斯的建议和评论之后,为什么下面的内容仍然会产生擦除警告:

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
    }
}
import reflect.runtime.universe_
特质属性{
受保护的def get(键:字符串):选项[属性]
def应用[A[x]一些(属性)
案例=>无
}
}
对我来说,这显然没有什么意义。一方面,我有
A[S]
的完整类型标记可用。另一方面,它甚至应该在没有它的情况下完全工作,因为
Attribute
S
中是不变的,所以如果我得到一个
选项[Attribute[S]
,并且我匹配
一些(attr:A[x])
,唯一的可能性是
x==S



编辑2:解决方案的条件是
属性
特征的形状不变,例如,不将类型构造函数参数
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: A[S]) => Some(attr)
      case _             => None
    }
}
trait属性[S]{
受保护的def get(键:字符串):选项[属性]
def apply[A[uu]Some(属性)
案例=>无
}
}
请注意,
A
type参数现在是一个高阶类型。因此,在
apply
方法中的每次出现时,您都需要将
A
应用到另一个类型,以获得正确的类型

此问题为更高阶类型提供了更多信息:


我认为您需要更高级的类型。我将您的代码改写为:

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
    }
}
trait属性[S]{
受保护的def get(键:字符串):选项[属性]
def apply[A[uu]Some(属性)
案例=>无
}
}
请注意,
A
type参数现在是一个高阶类型。因此,在
apply
方法中的每次出现时,您都需要将
A
应用到另一个类型,以获得正确的类型

此问题为更高阶类型提供了更多信息:


您是否考虑过利用隐式
类标记的
未应用
?如果我正确理解文档,如果
attr
与其类型不完全匹配,则标记中的
未应用
将返回一个None。如果匹配,它将返回某种类型的
a[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
  }
def apply[一个[]tag.unapply(属性)
案例=>无
}

您是否考虑过利用隐式
类标签的
未应用
?如果我正确理解文档,如果
属性
与其类型不完全匹配,则标签中的
未应用
将返回一个无。如果匹配,它将返回一个部分类型
a[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
  }
def apply[一个[]tag.unapply(属性)
案例=>无
}

单向。请注意,要将任何类型称为Int,甚至是嵌套类型,都需要一定的胆量

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
}
导入scala.reflect_
封闭性状属性{
S型
}
对象属性{
trait Int扩展属性{type S=Int}
}
/**特定类型属性的容器。
*/
特质属性[E]{
类型Attr=属性{type S None
}
}
性状测试2{
/**将键映射到int*/
def映射:属性[Int]
/**检索一个值*/
map[Attribute.Ints](“foo”)//使用部分应用的属性类型
}

单向。请注意,要将任何类型称为Int,甚至是嵌套类型,都需要一定的胆量

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
}
导入scala.reflect_
封闭性状属性{
S型
}
对象属性{
trait Int扩展属性{type S=Int}
}
/**特定类型属性的容器。
*/
特质属性[E]{
类型Attr=属性{type S None
}
}
性状测试2{
/**将键映射到int*/
def映射:属性[Int]
/**检索一个值*/
map[Attribute.Ints](“foo”)//使用部分应用的属性类型
}

这只是为了表明@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]("???")}")
}
//属性映射界面

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

这只是为了表明@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]("???")}")
}
//属性映射界面

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

这个版本的问题是,类标记没有在这里生效:
警告:抽象类型模式A[S]未被选中,因为它被擦除消除了。
。是的,这很奇怪。如果我添加了
println(标记)
apply
方法中,它打印了正确的类型名,所以我不知道是怎么回事。也许它应该提升到它自己的so问题。使用
TypeTag
ClassTags
只捕获被擦除的类型。@gzm0是的,我尝试过了。但是,关于擦除的警告没有发出。这个版本的问题是ClassTag在这里不起作用:
警告:抽象类型模式A[S]未被选中,因为它被擦除消除了。
。是的,这很奇怪。如果我添加
println(标记)
apply
方法中,它打印了正确的类型名,所以我不知道是怎么回事。也许它应该提升到它自己的so问题。使用
TypeTag
ClassTags
只捕获被擦除的类型。@gzm0是的,我尝试过了。但是关于擦除的警告不会消失。移动
s