tipos inteligencia imprimir funciones ejemplos datos composicion comentarios comandos artificial haskell functional-programming programming-languages newtype

inteligencia - imprimir en haskell



¿Qué lenguajes de programación tienen algo como el `newtype` de Haskell? (5)

Creo que las clases de valor de Scala satisfacen estas condiciones.

Por ejemplo:

case class Kelvin(k: Double) extends AnyVal

Edición: en realidad, no estoy seguro de que las conversiones tengan cero gastos generales en todos los casos. Esta documentation describe algunos casos en los que es necesaria la asignación de objetos en el montón, por lo que supongo que en esos casos habría una sobrecarga en tiempo de ejecución para acceder al valor subyacente desde el objeto.

El lenguaje de programación Haskell tiene un concepto de newtypes : si escribo newtype Foo = Foo (Bar) , entonces se crea un nuevo tipo Foo que es isomorfo a Bar , es decir, hay conversiones biyectivas entre los dos. Las propiedades de este constructo son:

  • Los dos tipos son completamente separados (es decir, el compilador no le permitirá usar uno donde se espera el otro, sin usar las conversiones explícitas).
  • Ellos comparten la misma representación. En particular, las funciones de conversión tienen un costo en tiempo de ejecución de cero y devuelven "el mismo objeto" en el montón.
  • La conversión solo es posible entre estos tipos y no se puede utilizar incorrectamente, es decir, la seguridad del tipo se conserva.

¿Qué otros lenguajes de programación proporcionan esta característica?

Un ejemplo parece ser las estructuras de valor único en C cuando se usan solo con los registros de acceso / constructores. Los candidatos no válidos serían estructuras de un solo valor en C cuando se usen con conversiones, ya que el compilador no verifica las conversiones u objetos con un solo miembro en Java, ya que no compartirían la misma representación.

Preguntas relacionadas: ¿F # tiene ''newtype'' de Haskell? (No) y D tiene ''newtype''? (ya no).


Rust siempre le ha permitido crear tipos de campo único, pero con el atributo repr(transparent) recientemente estabilizado, ahora puede estar seguro de que el tipo creado tendrá el diseño de datos exacto como el tipo ajustado, incluso en FFI y demás.

#[repr(transparent)] pub struct FooWrapper(Foo);


Go tiene esto:

Si declaramos

type MyInt int var i int var j MyInt

entonces tengo el tipo int y j tiene el tipo MyInt. Las variables i y j tienen distintos tipos estáticos y, aunque tienen el mismo tipo subyacente, no pueden asignarse entre sí sin una conversión.

"El mismo tipo subyacente" significa que la representación en la memoria de un MyInt es exactamente la de un int . Pasar un MyInt a una función que espera un int es un error en tiempo de compilación. Lo mismo es cierto para los tipos compuestos, por ejemplo, después de

type foo struct { x int } type bar struct { x int }

no se puede pasar una bar a una función que espera un foo ( test ).


Mercury es un lenguaje de programación de lógica pura, con un sistema de tipos similar al de Haskell.

La evaluación en Mercury es estricta en lugar de perezosa, por lo que no habría una diferencia semántica entre los equivalentes de Mercury de newtype y data . En consecuencia, cualquier tipo que tenga un solo constructor con un solo argumento se representa de manera idéntica al tipo de ese argumento, pero aún se trata como el mismo tipo; efectivamente "newtype" es una optimización transparente en Mercury. Ejemplo:

:- type wrapped ---> foo(int) ; bar(string). :- type wrapper ---> wrapper(wrapped). :- type synonym == wrapped.

La representación de la wrapper será idéntica a la de la wrapped pero es un tipo distinto, a diferencia del synonym que es simplemente otro nombre para el tipo wrapped .

Mercurio utiliza punteros etiquetados en sus representaciones. 1 Al ser estricto y tener diferentes representaciones para diferentes tipos, Mercury generalmente trata de eliminar el boxeo cuando es posible. p.ej

  • Para referirse a un valor de tipo "enumeración" (todos los constructores nulos) no necesita apuntar a ninguna memoria para poder usar el valor de los bits de etiqueta de una palabra completa para decir qué constructor es y en línea que en el referencia
  • Para hacer referencia a una lista, puede usar un puntero etiquetado a una celda contras (en lugar de un puntero a una estructura que contiene la información sobre si es nula o una celda contras)
  • etc

La optimización "newtype" es en realidad solo una aplicación particular de esa idea general. El tipo "envoltorio" no necesita ninguna celda de memoria asignada por encima de lo que ya contiene el tipo "envuelto". Y como necesita cero bits de etiqueta, también puede encajar en cualquier etiqueta en la referencia al tipo "envuelto". Por lo tanto, toda la referencia al tipo "envuelto" se puede insertar en la referencia al tipo de envoltura, que termina siendo indistinguible en el tiempo de ejecución.

1 Los detalles aquí solo pueden aplicarse a los grados de compilación de C de bajo nivel. Mercury también puede compilar a "alto nivel" C o a Java. Obviamente, no hay ningún problema con Java (aunque, por lo que sé, todavía se aplica la optimización del "nuevo tipo"), y estoy menos familiarizado con los detalles de la implementación en los grados de alto nivel.


Frege tiene esto, sin embargo, a diferencia de Haskell, no hay una palabra clave adicional. En su lugar, cada tipo de producto con un solo componente es un nuevo tipo.

Ejemplo:

data Age = Age Int

Además, todos los lenguajes que tienen tipificación nominal y permiten definir un tipo en términos de otro deben tener esta característica. Por ejemplo Oberon, Modula-2 o ADA. Así que después

type age = integer; {* kindly forgive syntax errors *}

Uno no podría confundir una edad y alguna otra cantidad.