scala haskell types

Dentro de Scala, ¿es posible alias un tipo pero no permitir el uso cruzado de tipos alias/sin alias como Haskell?



types (2)

Sí, estás usando algo conocido como Tipos Tagged Unboxed en Scala.

Así es como se define Tagged:

type Tagged[U] = { type Tag = U } type @@[T, U] = T with Tagged[U]

Esto te permite hacer algo como esto

sealed trait Feet def Feet[A](a: A): A @@ Feet = Tag[A, Feet](a) Feet: [A](a: A)scalaz.@@[A,Feet] scala> val mass = Feet(20.0) mass: scalaz.@@[Double,Feet] = 20.0 scala> 2 * mass res2: Double = 40.0

para agregar también CM

sealed trait CM def CM[A](a: A): A @@ CM = Tag[A, CM](a) CM: [A](a: A)scalaz.@@[A,CM] scala> val mass = CM(20.0) mass: scalaz.@@[Double,CM] = 20.0

Si quieres restringir la multiplicación a solo Pies, entonces puedes escribir una función de multiplicación tipo tipo de letra

trait Multiply[T] { self => def multiply(a: T, b: T): T } implicit val footInstance = new Multiply[Feet] { def multiply(a: Feet, b: Feet): Feet = Feet(a * b) } implicit val cmInstance = new Multiply[CM] { def multiply(a: CM, b: CM): CM = CM(a * b) } def multiply[T: Multiply](a: T, b: T): T = { val multi = implicitly[Multiply[T]] multi.multiply(a,b) }

entonces puedes hacer

multiply(Feet(5), Feet(10)) // would return Feet(50)

esto es lo mejor que Scala puede hacer

Para obtener más información sobre el tipo de caja, echa un vistazo a http://eed3si9n.com/learning-scalaz-day3

En Haskell, creo que es posible aliar un tipo de tal manera que el compilador no permite referencias entre el tipo con alias y el tipo no alias. De acuerdo con esta pregunta de desbordamiento de pila , uno puede usar el newtype tipo de Haskell así:

newtype Feet = Feet Double newtype Cm = Cm Double

donde Feet y Cm se comportarán como valores dobles, pero intentar multiplicar un valor de Feet y un valor de Cm generará un error de compilación.

EDITAR: Ben señaló en los comentarios que esta definición anterior en Haskell es insuficiente. Feet y Cm serán nuevos tipos, en los cuales no habrá funciones definidas. Investigando un poco más, descubrí que lo siguiente funcionará:

newtype Feet = Feet Double deriving (Num) newtype Cm = Cm Double deriving (Num)

Esto crea un nuevo tipo que deriva del tipo Num existente (requiere el uso de switch: -XGeneralizedNewtypeDeriving ). Por supuesto, estos nuevos tipos serán aún más valiosos derivados de otros tipos, como Show , Eq , etc., pero este es el mínimo requerido para evaluar correctamente Cm 7 * Cm 9 .

Tanto Haskell como Scala tienen type , que simplemente alias un tipo existente y permite un código sin sentido como este ejemplo en Scala:

type Feet = Double type Cm = Double val widthInFeet: Feet = 1.0 val widthInCm: Cm = 30.48 val nonsense = widthInFeet * widthInCm def getWidthInFeet: Feet = widthInCm

¿Scala tiene un newtype equivalente, suponiendo que esto hace lo que creo que hace?


Otra opción sería usar clases de valor. Estos crean un contenedor alrededor de un tipo subyacente que se convierte en acceso directo al tipo sin procesar en tiempo de compilación, con métodos en la clase que se convierten en llamadas estáticas en un objeto complementario asociado. Por ejemplo:

class CM(val quant : Double) extends AnyVal { def +(b : CM) = new CM(quant + b.quant) def *(b : Int) = new CM(quant * b) }