I'm trying to work my way into understanding type-programming in Scala, and I've found that most of what one needs to know about type programming has an analogous counterpart in value programming as is reflected in the type-level programming wiki page. However, I've not found the analogy for the this
key word or self-types. I suspect maybe it doesn't make sense to expect such a thing, but I thought I would ask.
For instance, I can write the following to represent Booleans as values at run time:
sealed trait BoolVal {
def not:BoolVal
def or(that:BoolVal):BoolVal
def and(that:BoolVal) =
(this.not or that.not).not
def imp(that:BoolVal) =
this.not or that
}
case object TrueVal extends BoolVal {
override val not = FalseVal
override def or(that:BoolVal) = TrueVal
}
case object FalseVal extends BoolVal {
override val not = TrueVal
override def or(that:BoolVal) = that
}
Here my and
and imp
are able to take advantage of the fact it doesn't matter if I am a false object or a true object to be defined correctly. My TrueVal
and FalseVal
objects can inherit the same code.
I can make the analogous type-level programming constructs, but I don't understand how to define And
and Imp
in my base trait.
sealed trait BoolType {
type Not <: BoolType
type Or[That <: BoolType] <: BoolType
type And[That <: BoolType] = ???
type Imp[That <: BoolType] = ???
}
sealed trait TrueType extends BoolType {
override type Not = FalseType
override type Or[That <: BoolType] = TrueType
}
sealed trait FalseType extends BoolType {
override type Not = TrueType
override type Or[That <: BoolType] = That
}
I can see where perhaps it doesn't make sense that my types inherit types, but the certainly inherit abstract types. Is there a way to define And
and Impl
in my BoolType
, or do I have to define each in the respective TrueType
and FalseType
traits?
You can always define an abstract type on your boolean base type as follows:
trait MyBool extends BoolType{
type This <: BoolType
}
trait TrueType extends BoolType{
type This = TrueType
}
and you should be good to go with a reference to yourself. Then you can use DeMorgan's Laws to do the following
!(x && y) == (!x || !y)
Then by a double negative you can get you And
condition going:
!(!x || !y) == !!(x && y) == (x && y)
I would suggest using self
, example of your blog post adjusted:
sealed trait BoolType { self =>
type Not <: BoolType
type Or[That <: BoolType] <: BoolType
type And[That <: BoolType] = self.type#Not#Or[That#Not]#Not
type Imp[That <: BoolType] = self.type#Not#Or[That]
}
sealed trait TrueType extends BoolType {
override type Not = FalseType
override type Or[That <: BoolType] = TrueType
}
sealed trait FalseType extends BoolType {
override type Not = TrueType
override type Or[That <: BoolType] = That
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With