是否可以在 Scala 3 中实现防故障
Not[A]
类型?
这是几年前提出的一个问题:我如何在 scala 中拥有否定类型。
不幸的是,如果其中任何一个是抽象类型,基于“未给出A <:< B
”的解决方案就会失败:缺乏证据不是缺乏证据的谬误。从技术上讲,
使用宏,应该可以验证表达式的类型并在不知道完整类型信息时产生错误。但是,我希望它不仅在“不是A <:< B
”时也能工作,而且只有在A with B
有效Nothing
时才有效:任何一种类型都是密封/最终的,不能混入另一种。另一方面,在那种情况下,不应该需要有关这两种类型的完整信息:如果 A 是最终的,则 B 的任何上限既不是类型变量也不是 A
应该有效。
动机:
sealed trait Marker
sealed trait A[X]
final class Special[X <: Marker] extends A[X]
final class Generic[X :Not[Marker]#Proof] extends A[X]
在上面的例子中,如果我有一个
a :A[Marker]
,那么我肯定知道a.asInstanceOf[Special[Marker]]
是正确的。
类型类
Not
不能用 Scala 3 隐式定义。歧义把戏不再奏效了。隐式解析的语义发生了变化。不传播歧义错误。
Scala 2 implicits 和 Scala 3 given/using 之间的区别 (answer)
这就是为什么在 Scala 3 中内置
Not
的原因:scala.util.NotGiven
https://docs.scala-lang.org/scala3/reference/contextual/givens.html#negated-givens
https://docs.scala-lang.org/scala3/reference/changed-features/implicit-resolution.html
并非所有具有类型类的语言
Not
都是可能的。例如在 Haskell 中这是不可能的(使用标准工具)
如何实现`Constraint`反射? [基于可用约束的 Ad-Hoc 多态性]
你可以尝试类似的东西
import scala.util.NotGiven
import scala.compiletime.summonFrom
final class Generic[X](using (NotGiven[X <:< Marker] || IsAbstract[X])) extends A[X]
trait ||[A, B]
object ||:
transparent inline given [A, B]: (A || B) =
summonFrom {
case _: A => new (A || B) {}
case _: B => new (A || B) {}
}
import scala.quoted.*
trait IsAbstract[X]
object IsAbstract:
transparent inline given [X]: IsAbstract[X] = ${mkIsAbstractImpl[X]}
def mkIsAbstractImpl[X: Type](using Quotes): Expr[IsAbstract[X]] =
import quotes.reflect.*
val tpe = TypeRepr.of[X]
if tpe.typeSymbol.isAbstractType
then '{new IsAbstract[X] {}}
else report.errorAndAbort(s"${tpe.show} is not abstract")
普通的union类型
NotGiven[X <:< Marker] | IsAbstract[X]
不优先类型类的实例,因此导致歧义。
如有必要,您可以添加
IsSealed
,IsFinal
等