¿Cuál es la analogía de programación de tipo Scala para la palabra clave `this`?
types metaprogramming (3)
Estoy tratando de abrirme camino para comprender la programación de tipos en Scala, y he descubierto que la mayor parte de lo que se necesita saber acerca de la programación de tipos tiene una contraparte análoga en la programación de valores, como se refleja en la página de la wiki de programación de nivel . Sin embargo, no he encontrado la analogía para this
palabra clave o auto-tipos. Sospecho que tal vez no tenga sentido esperar tal cosa, pero pensé que iba a preguntar.
Por ejemplo, puedo escribir lo siguiente para representar valores booleanos como valores en tiempo de ejecución:
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
}
Aquí mi imp
son capaces de aprovechar el hecho de que no importa si soy un objeto falso o un objeto verdadero para ser definido correctamente. FalseVal
objetos My TrueVal
y FalseVal
pueden heredar el mismo código.
Puedo hacer construcciones de programación de nivel de tipo análogas, pero no entiendo cómo definir And
e Imp
en mi rasgo base.
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
}
Puedo ver dónde quizás no tiene sentido que mis tipos hereden tipos, pero ciertamente heredan tipos abstractos. ¿Hay alguna manera de definir And
e Impl
en mi BoolType
, o tengo que definir cada uno en los respectivos caracteres TrueType
y FalseType
?
¿Por qué no usar this
palabra clave? Cuando exploré la programación de nivel de tipo, no pude ver una diferencia al usar esto en lugar de uno mismo.
sealed trait BoolType {
type Not <: BoolType
type Or[That <: BoolType] <: BoolType
type And[That <: BoolType] = this.type#Not#Or[That#Not]#Not
type Imp[That <: BoolType] = this.type#Not#Or[That]
}
Siempre puede definir un tipo abstracto en su tipo base booleana de la siguiente manera:
trait MyBool extends BoolType{
type This <: BoolType
}
trait TrueType extends BoolType{
type This = TrueType
}
y debes ser bueno para ir con una referencia a ti mismo. Luego puede usar las leyes de DeMorgan para hacer lo siguiente
!(x && y) == (!x || !y)
Luego, con un doble negativo, puedes ponerte en condiciones:
!(!x || !y) == !!(x && y) == (x && y)
Sugeriría usar self
, ejemplo de tu blog ajustado:
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
}