Just playing around with some Scala 3 features, I'm defining a BooleanAlgebra[A]
in which there is T <: A
and B <: A
. These types are used to check if the type A has been normalized and we no longer need to check the bounds of it.
Normailize gives us T | F
T | F
TypeTests are required of course because the types T
and F
are erased at runtime.
The sample works without a problem, however it complains that the matches are not exhaustive anytime I match against T | F
T | F
even though there is a TypeTag from T | F => T
T | F => T
and from T | F => F
T | F => F
. Note I've added println
statements so that you can see it work.
Adding TypeTags from A => T | F
A => T | F
, A => T
and A => F
don't work either. N is required due to the fact that Scala 3 doesn't seem to like to do this calculation over something that can change. In the Peano example on the Dotty site, if you switch it to Peano[A] it will stop matching properly, but if you add type NAT = A
it works fine.
Any thoughts about how this can be made to match properly would be appreciated.
Here is the code sample:
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)
}
Example implementation
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
}
With the following code, I'm NOT getting any warnings with scala 3.0.2 (and I WAS getting them with 3.0.0):...
I had to make several minor modifications, first in the trait I've defined N
as T | F
T | F
, and used it everywhere:
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
Then, I've defined extension(s) in the object (so moved them from the trait) in a slightly different manner (had to change names for |
and &
to prevent calls to existing functions in Int
too). Also in the object, I've defined not
(which you had), and
and or
functions (although they are not needed for the test):
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)
Example usage, with:...
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
I can do something like this for example (comments regarding use of TypeTest
within code):...
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)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.