Scala编译器扩展类型 [英] Scala compiler expand types

查看:55
本文介绍了Scala编译器扩展类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

  trait TypeOr[E, F] {
    type T
  }

  implicit def noneq2[E, F](implicit ev: E =!= F): TypeOr[E, F] = new TypeOr[E, F] {
    type T = (E, F)
  }

  sealed trait Error[+E, +A]

  case class Err[E, A](e: Error[E, A]) {
    def combine[B, F](f: A => Error[F, B])(implicit ev: TypeOr[E, F]): Error[ev.T, B] = ???
  }
  val result = Err(null.asInstanceOf[Error[Int, Int]]).combine(_ => null.asInstanceOf[Error[String, String]])

到目前为止,一切都很好.根据以上定义,我得出结论,结果的扩展类型如下:

So far so good. From the definitions above, I concluded, that the expanded type of the result is following:

  val itsType: Error[(Int, String), String] = result

但是显然不是,因为编译器会回复:

But apparently it is not, since the compiler replies with:

 found   : returnerror.Comb.Error[returnerror.Comb.TypeOr[Int,String]#T,String]
 required: returnerror.Comb.Error[(Int, String),String]
  val itsType: Error[(Int, String), String] = result

是否可以找出表达式的简化-扩展类型?我无法从编译器获得此信息,我试图在擦除阶段之前打印AST,但是扩展类型仍然不存在.

Is it possible to find out the simplified - expanded type of the expression? I can't get this information from compiler, I tried to print the AST before the erasure phase, but the expanded type is still not there.

推荐答案

首先,当您编写隐式 noneq2 的类型为 TypeOr [E,F] 时,您会丢失类型优化 https://typelevel.org/blog/2015/07/19/forget-refinement-aux.html .正确是

Firstly, when you write that implicit noneq2 has type TypeOr[E, F] you lost type refinement https://typelevel.org/blog/2015/07/19/forget-refinement-aux.html . Correct is

implicit def noneq2[E, F](implicit ev: E =:!= F) = new TypeOr[E, F] {
  type T = (E, F)
}

或使用显式类型更好

implicit def noneq2[E, F](implicit ev: E =:!= F): TypeOr[E, F] { type T = (E, F) }  = new TypeOr[E, F] {
  type T = (E, F)
}

这就是通常引入 Aux 类型的原因

That's the reason why usually type Aux is introduced

object TypeOr {
  type Aux[E, F, T0] = TypeOr[E, F] { type T = T0 }

  implicit def noneq2[E, F](implicit ev: E =:!= F): Aux[E, F, (E, F)] = new TypeOr[E, F] {
    type T = (E, F)
  }
}

第二,自动推断 result 的类型,即 Error [TypeOr [Int,String] #T,String] (类型投影 TypeOr [Int,String]#T (yT forSome {val y:TypeOr [Int,String]})的超类型,而且 xT 的父类型也太粗糙了 https://typelevel.org/blog/2015/07/23/type-projection.html

Secondly, automatically inferred type of result i.e.Error[TypeOr[Int, String]#T, String] (type projection TypeOr[Int,String]#T is a supertype of (y.T forSome { val y: TypeOr[Int, String] }) and moreover of x.T) is too rough https://typelevel.org/blog/2015/07/23/type-projection.html

最好为 result 编写与路径相关的类型.

It's better to write path-dependent type for result.

但是

val x = implicitly[TypeOr[Int, String]]
val result: Error[x.T, String] =
  Err(null.asInstanceOf[Error[Int, Int]]).combine(_ => null.asInstanceOf[Error[String, String]])

不编译.

问题是隐式会破坏类型细化 https://typelevel.org/blog/2014/01/18/implicitly_existential.html

The thing is that implicitly can damage type refinements https://typelevel.org/blog/2014/01/18/implicitly_existential.html

这就是为什么存在宏 shapeless.the .

val x = the[TypeOr[Int, String]]
val result: Error[x.T, String] = Err(null.asInstanceOf[Error[Int, Int]]).combine(_ => null.asInstanceOf[Error[String, String]])
val itsType: Error[(Int, String), String] = result

或者,可以定义自定义实现器

Alternatively, custom materializer can be defined

object TypeOr {
  //...
  def apply[E, F](implicit typeOr: TypeOr[E, F]): Aux[E, F, typeOr.T] = typeOr
}

val x = TypeOr[Int, String]
val result: Error[x.T, String] =
  Err(null.asInstanceOf[Error[Int, Int]]).combine(_ => null.asInstanceOf[Error[String, String]])
val itsType: Error[(Int, String), String] = result

这篇关于Scala编译器扩展类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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