【问题标题】:Scala 3 TypeTest over Union doesn't seem to work correctlyScala 3 TypeTest over Union 似乎无法正常工作
【发布时间】:2021-08-11 14:16:58
【问题描述】:

只是玩弄一些 Scala 3 功能,我定义了一个 BooleanAlgebra[A],其中有 T <: AB <: A。这些类型用于检查类型 A 是否已经归一化,我们不再需要检查它的边界。

Normailize 给我们T | F 当然需要 TypeTest,因为 TF 类型在运行时会被删除。

该示例可以正常工作,但它抱怨无论何时我与T | F 匹配时匹配并不详尽,即使有来自T | F => TT | F => F 的TypeTag。请注意,我添加了 println 语句,以便您可以看到它的工作原理。

A => T | FA => TA => F 添加 TypeTag 也不起作用。 N 是必需的,因为 Scala 3 似乎不喜欢对可能改变的东西进行这种计算。在 Dotty 网站上的 Peano 示例中,如果将其切换为 Peano[A],它将停止正确匹配,但如果添加 type NAT = A 则可以正常工作。

任何关于如何使其正确匹配的想法将不胜感激。

这是代码示例:

trait BooleanAlgebra[A] {
  final type N = A
  type T <: N
  type F <: N

  val tru: T
  val fls: F

  final given TypeTest[T | F, T] =
    x =>
      println(" => T")
      if x == tru then Some(tru.asInstanceOf[x.type & T])
      else None

  final given TypeTest[T | F, F] =
    x =>
      println(" => F")
      if x == fls then Some(fls.asInstanceOf[x.type & F])
      else None

  def normalize(value: N): T | F

  final def not(value: T | F): T | F =
    value match
      case _: T => fls
      case _: F => tru

  final def and(lhs: => T | F, rhs: => T | F): T | F =
    lhs match
      case _: T => rhs
      case _: F => fls

  final def or(lhs: => T | F, rhs: => T | F): T | F =
    lhs match
      case _: T => tru
      case _: F => rhs

  extension (lhs: => T | F) {
    final def unary_! : T | F =
      not(lhs)

    final def |(rhs: => T | F): T | F =
      or(lhs, rhs)

    final def &(rhs: => T | F): T | F =
      and(lhs, rhs)
  }
}

object BooleanAlgebra {
  def tru[A](using b: BooleanAlgebra[A]): b.T =
    b.tru

  def fls[A](using b: BooleanAlgebra[A]): b.F =
    b.fls

  def not[A](using b: BooleanAlgebra[A]): b.T | b.F => b.T | b.F =
    value =>
      b.not(value)

  def norm[A](value: A)(using b: BooleanAlgebra[A]): b.T | b.F =
    b.normalize(value)
}

示例实现

given BooleanAlgebra[Int] with {
  type T = 1
  type F = 0

  val tru = 1
  val fls = 0

  def normalize(value: Int) =
    if value > 0 then tru
    else fls
}

【问题讨论】:

    标签: scala union-types scala-3


    【解决方案1】:

    使用以下代码,我不会在 scala 3.0.2 中收到任何警告(我WAS在 3.0.0 中收到警告):...

    我必须做一些小的修改,首先是我将N定义为T | F的特征,并在任何地方使用它:

    trait BooleanAlgebra [A]:
       type T <: A
       type F <: A
       type N = T | F
    
       val tru: T
       val fls: F
    
       final given TypeTest [N, T] =
          x =>
             print ("=> T ")
             if x == tru then
                Some (tru.asInstanceOf [x.type & T])
             else
                None
    
       final given TypeTest [N, F] =
          x =>
             print ("=> F ")
             if x == fls then
                Some (fls.asInstanceOf [x.type & F])
             else
                None
    
       def normalize (value: A): N
    
       final def not (v1: => N): N =
          v1 match
             case _: T => fls
             case _: F => tru
    
       final def and (v1: => N, v2: => N): N =
          v1 match
             case _: T => v2
             case _: F => fls
    
       final def or (v1: => N, v2: => N): N =
          v1 match
             case _: T => tru
             case _: F => v2
    

    然后,我以稍微不同的方式在对象中定义了扩展(因此将它们从特征中移出)(必须更改 |&amp; 的名称以防止调用 @ 中的现有函数987654326@ 也是)。同样在对象中,我定义了not(你有)、andor 函数(尽管测试不需要它们):

    object BooleanAlgebra:
       def tru [A] (using b: BooleanAlgebra [A]): b.T =
          b.tru
    
       def fls [A] (using b: BooleanAlgebra [A]): b.F =
          b.fls
    
       def norm [A] (value: A) (using b: BooleanAlgebra [A]): b.N =
          b.normalize (value)
    
       extension [A] (using b: BooleanAlgebra [A]) (v1: => b.N)
       {
          final def unary_! : b.N =
             b.not (v1)
    
          final def &&& (v2: => b.N): b.N =
             b.and (v1, v2)
    
          final def ||| (v2: => b.N): b.N =
             b.or (v1, v2)
       }
    
       def not [A] (using b: BooleanAlgebra [A]): b.N => b.N =
          v1 => b.not (v1)
    
       def and [A] (using b: BooleanAlgebra [A]): (b.N, b.N) => b.N =
          (v1, v2) => b.and (v1, v2)
    
       def or [A] (using b: BooleanAlgebra [A]): (b.N, b.N) => b.N =
          (v1, v2) => b.or (v1, v2)
    

    示例用法,有:...

       given BooleanAlgebra [Int] with
          type T = 1
          type F = 0
    
          val tru = 1
          val fls = 0
    
          def normalize (value: Int): N =
             if (value > 0) then 1 else 0
    

    例如,我可以做这样的事情(关于在代码中使用TypeTest 的cmets):...

       def test () (using ba: BooleanAlgebra [Int]): Unit =
          import ba._
          val a1 = 4
          val n1 = normalize (a1)
          // this will print normalized value of 1
          println (n1)
          // following not call will make a single type test for T
          val n2 = !n1
          println (n2)
          // following two calls will make 1 type test each, for T only
          println (n1 &&& n2)
          println (n1 ||| n2)
          // following two calls will make 2 type tests each, both for T (failing) and then F
          println (n2 &&& n1)
          println (n2 ||| n1)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-04
      • 2012-05-06
      • 2013-02-17
      • 2017-10-09
      • 2017-08-03
      • 2014-05-02
      • 2011-09-11
      相关资源
      最近更新 更多