我们可以在Scala中定义一个更高级的类型级恒等函数吗?

b5buobof  于 2023-04-12  发布在  Scala
关注(0)|答案(4)|浏览(134)

在Scala中,我们可以为低级类型定义类型级恒等函数,如下所示:

type Id[A] = A

我们是否也可以为更高级别的类型定义类似的东西?即,我们是否可以填写以下空白:

type HKId[A[...]] = ...

所以类似于HKId[List]的东西会让我们回到List类型构造函数?
自由名称的绑定,例如

type Foo[X] = List[X]
val l : Foo[Int] = List(1, 2, 3)

可能会让我们认为一个更高级的类型层次的身份看起来像

type HKId[A[X]] = A[X]

但是scalac抱怨在RHS上找不到类型X。
有没有一些聪明的编码可以做到这一点?或者只是现在不可能?

qvtsj1bj

qvtsj1bj1#

type HKId[A[X]] = ...中的X是一个高阶类型参数。它的作用域是类型参数子句,通常在类型约束中引用。参见规范的§4.4:
上述作用域限制被推广到嵌套类型参数子句的情况,嵌套类型参数子句声明更高阶的类型参数。(类型参数t的类型参数)仅在其紧邻的parameter子句中可见(可能包括更深嵌套级别处的子句)并且在t的边界中。因此,它们的名称必须与其他可见参数的名称成对不同。由于高阶类型参数的名称因此通常是不相关的,因此它们可以用'_'表示,这在任何地方都不可见。
不久前,我们讨论了为类型函数添加文字语法的可能性,例如[A] Either[Int, A]。这在Scalaz中非常有用。同时,我们使用Alexey的答案中的技巧,用PartialApplyXofY traits表示。推理会更好,但这要棘手得多,尽管有innocuous entry in Trac!)
无论如何,在该线程中,Adriaan mentioned
显然,实现匿名类型函数逻辑上的所有内容并不容易,因为我们目前还没有必要的基础设施来允许人们编写更高级的类型别名,例如:
type MyTypeFun = [X,Y] Pair[Y,X] //可取,但难以用当前实现支持(我们查看符号的类型参数来推断其种类)

更新

事实证明,你已经可以非常接近了:

def hk[_[_]] = (); 
hk[({type A[X] = X})#A]

或者来点创意:

def hk[_[_]] = (); hk[({type \[X] = X}) # \ ]
def hk[_[_]] = (); hk[({type λ[α]=α})#λ ]
lrl1mhuk

lrl1mhuk2#

找不到一种方法来做一个type,但这工作:

class HKId[A[_]] { 
  type Value[X] = A[X] 
}

这编译:

scala> List(1): HKId[List]#Value[Int]
res2: List[Int] = List(1)

而这并不:

scala> List(1): HKId[List]#Value[Boolean]
<console>:7: error: type mismatch;
 found   : Int(1)
 required: Boolean
       List(1): HKId[List]#Value[Boolean]
7qhs6swi

7qhs6swi3#

从@retronym那里抢走正确答案似乎有点不公平,但看起来我们可以更接近我所追求的那种解决方案,

scala> type HKId[A[_]] = { type λ[X] = A[X] }
defined type alias HKId

scala> def foo[C[_]] : C[Int] = null.asInstanceOf
foo: [C[_]]=> C[Int]

scala> foo[List]
res0: List[Int] = null

scala> foo[HKId[List]#λ]
res1: List[Int] = null

我不知道为什么这在现在看起来很明显,但在一年前并不明显......也许是因为从那时起我们都更习惯于看到类型lambda。

k75qkfdt

k75qkfdt4#

在Scala 3中,type HKId[A[_]] = A仍然是不允许的,但以下所有类型声明都可以工作

type HKId[A[_]] = [X] =>> A[X]

type HKId = [A[_]] =>> [X] =>> A[X]

type HKId[A[_]] = A[*]  // scalacOptions += "-Ykind-projector"

Polymorphic method works with type lambda, but not with type wildcard in Scala 3
Scala 3.2.2(scastie
另一种选择是使Id成为poly-kind

type Id[A <: AnyKind] = A

相关问题