Dotty提供什么来代替类型投影? [英] What does Dotty offer to replace type projections?

查看:138
本文介绍了Dotty提供什么来代替类型投影?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读有关Dotty的内容,因为它看起来将成为scala 3,并且注意到类型投影被认为是不合理的",并已从语言中删除...

I have been reading about Dotty, since it looks like it is about to become scala 3, and noticed that type projections are deemed "unsound" and removed from the language ...

这似乎简直是无赖,因为我已经看到了几个用例真正有用的地方.例如:

This seems like a bummer, as I have seen several use cases where they were really useful. For example:

trait Contents
class Foo extends Contents
class Bar extends Contents

trait Container[T <: Contents] { type ContentType = T }
class FooContainer extends Container[Foo]
class BarContainer extends Container[Bar]

trait Manager[T <: Container[_]] { 
  type ContainerType = T 
  type ContentType = T#ContentType
  def getContents: ContentType 
  def createContainer(contents: ContentType): ContainerType
}

在Dotty中如何做这样的事情?在Manager中添加第二个类型参数?但是,除了它使创建和操作Manager的实例变得非常繁琐的事实外,它还不太有效,因为没有办法强制两种类型之间的关系(Manager[FooContainer, Bar]不应合法).

How would one do something like this in Dotty? Add a second type parameter to Manager? But, aside from the fact that it makes it really tedious to create and manipulate instances of the Manager, it also doesn't quite work, as there is no way to enforce the relationship between the two types (Manager[FooContainer, Bar] should not be legal).

然后,还有其他用途(例如lambda类型和部分应用的类型)可用于创建有偏函子等……还是这些(部分应用的类型)成为Dotty中的头等公民"?

Then, there are other uses, like type lambdas, and partially applied types, that are useful for creating biased functors etc ... Or do these (partially applied types) become "first class citizens" in Dotty?

编辑

要回答评论中的问题,以下是他可以使用的一些人为设计的示例.假设我的Managers实际上是Akka Actors:

To answer the question in the comments, here is a somewhat contrived example of his this may be used. Let's suppose, my Managers are actually Akka Actors:

abstract class BaseManager[T <: Container[_]](
  val storage: ContentStorage[T#ContentType]
) extends Actor with Manager[T] {
    def withContents(container: T, content: ContentType): ContainerType
    def withoutContents: T

    var container: T = withoutContents

    def receive: Receive {
       case ContentsChanged => 
          container = withContents(container, storage.get)
       case ContainerRequester => 
           sender ! container
       // ... other common actions 
    }
}

class FooManager(storage: FooStorage) extends BaseManager[FooContainer](storage) {
   def withContents(container: FooContainer, content: Foo) = 
       container.copy(Some(content))
   def withoutContent = FooContainer(None)

   override def receive: Receive = super.receive orElse { 
    // some additional actions, specific to Foo
   }
}

case class FooContainer(content: Option[Foo]) extends Container[Foo]{
  // some extremely expensive calculations that happen when 
  // content is assigned, so that we can cache the result in container
}

推荐答案

在Scala 2.12中,类型投影有时可以替换为类型类+依赖于路径的类型

In Scala 2.12 type projections sometimes can be replaced with type class + path-dependent types

trait ContentType[T <: Container[_]] {
  type Out
}
object ContentType {
  type Aux[T <: Container[_], Out0] = ContentType[T] { type Out = Out0 }
  def instance[T <: Container[_], Out0]: Aux[T, Out0] = new ContentType[T] { type Out = Out0 }

  implicit def mk[T <: Contents]: Aux[Container[T], T] = instance
}

abstract class Manager[T <: Container[_]](implicit val contentType: ContentType[T]) {
  type ContainerType = T
  def getContents: contentType.Out
  def createContainer(contents: contentType.Out): ContainerType
}


在Dotty 0.16.0-bin-20190529-3361d44-NIGHTLY中检查(在0.16.0-RC3中,delegate应该代替implied)


Checked in Dotty 0.16.0-bin-20190529-3361d44-NIGHTLY (in 0.16.0-RC3 delegate should be instead of implied)

trait Contents
class Foo extends Contents
class Bar extends Contents

trait Container[T <: Contents] { type ContentType = T }
class FooContainer extends Container[Foo]
class BarContainer extends Container[Bar]

trait ContentType[T <: Container[_]] {
  type Out
}
object ContentType {
  implied [T <: Contents] for ContentType[Container[T]] {
    type Out = T
  }
}

trait Manager[T <: Container[_]] given (val contentType: ContentType[T]) {
  type ContainerType = T
  type ContentType = contentType.Out
  def getContents: ContentType
  def createContainer(contents: ContentType): ContainerType
}


另一种选择是使用匹配类型

trait Contents
class Foo extends Contents
class Bar extends Contents

trait Container[T <: Contents] { type ContentType = T }
class FooContainer extends Container[Foo]
class BarContainer extends Container[Bar]

type ContentType[T <: Container[_]] = T match {
  case Container[t] => t
}

trait Manager[T <: Container[_]] {
  type ContainerType = T
  def getContents: ContentType[T]
  def createContainer(contents: ContentType[T]): ContainerType
}

这篇关于Dotty提供什么来代替类型投影?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆