加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Scala列出了存在类型:`map {case t => …}`works,`map {t =&

发布时间:2020-12-16 08:46:21 所属栏目:安全 来源:网络整理
导读:假设我们已经定义了一个存在类型: type T = (X = X,X) forSome { type X } 然后定义List [T]类型的列表: val list = List[T]( ((x: Int) = x * x,42),((_: String).toUpperCase,"foo")) 众所周知[1],[2]以下尝试映射不起作用: list.map{ x = x._1(x._2) }
假设我们已经定义了一个存在类型:

type T = (X => X,X) forSome { type X }

然后定义List [T]类型的列表:

val list = List[T](
  ((x: Int) => x * x,42),((_: String).toUpperCase,"foo")
)

众所周知[1],[2]以下尝试映射不起作用:

list.map{ x => x._1(x._2) }

但是,为什么以下工作呢?:

list.map{ case x => x._1(x._2) }

请注意,两个链接问题的答案都假定模式匹配中需要一个类型变量,但它也可以在没有类型变量的情况下工作.问题的重点在于为什么{case x => ……}工作?

解决方法

(我自己试图回答这个问题;应该不是太错了,但也许有点肤浅.)

首先,观察一下

list.map{ x => x._1(x._2) }
list.map{ case x => x._1(x._2) }

与…基本相同

list map f1
list map f2

val f1: T => Any = t => t._1(t._2)
val f2: T => Any = _ match {
  case q => q._1(q._2)
}

实际上,f1的编译失败了,而f2成功了.

我们可以看到为什么f1的编译必须失败:

> t是类型(X => X,X)的某些{类型X}
>因此,推断第一个组件t._1具有类型(X => X)的某些{类型X}.
>同样,推断第二个组件t._2的类型为X forSome {type X},它只是Any.
>我们不能将(X => X)forSome {type X}应用于Any,因为对于某些SuperSpecialType,它实际上可能会变成(SuperSpecialType => SuperSpecialType).

因此,f1的编译应该失败,它确实会失败.

要了解为什么f2成功编译,可以查看类型检查器的输出.如果我们将其保存为someFile.scala:

class O {
  type T = (X => X,X) forSome { type X }

  def f2: T => Any = t => t match {
    case q => q._1(q._2)
  }

  def f2_explicit_func_arg: T => Any = t => t match {
    case q => {
      val f = q._1
      val x = q._2
      f(x)
    }
  }
}

然后使用生成typechecker的输出

$scalac -Xprint:typer someFile.scala

我们获得了基本上(删除了一些噪音):

class O extends scala.AnyRef {
  type T = (X => X,X) forSome { type X };
  def f2: O.this.T => Any = ((t: O.this.T) => t match {
    case (q @ _) => q._1.apply(q._2)
  });
  def f2_explicit_func_arg: O.this.T => Any = ((t: O.this.T) => t match {
    case (q @ _) => {
      val f: X => X = q._1;
      val x: X = q._2;
      f.apply(x)
    }
  })
}

第二个f2_explicit_func_arg版本(相当于f2)比较短的原始f2版本更具启发性.在f2_explicit_func_arg的desugared和类型检查代码中,我们看到类型X奇迹般地再次出现,并且类型检查器确实推断:

f: X => X
x: X

所以f(x)确实有效.

在使用显式命名的类型变量的更明显的解决方法中,我们手动执行编译器在这种情况下为我们做的事情.

我们也可以写:

type TypeCons[X] = (X => X,X)
list.map{ case t: TypeCons[x] => t._1(t._2) }

甚至更明确地:

list.map{ case t: TypeCons[x] => {
  val func: x => x = t._1
  val arg: x = t._2
  func(arg)
}}

并且这两个版本的编译原因与f2非常相似.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读