Articulo de referencia

Sistema de tipos subestructurales

Los sistemas de tipos subestructurales son una familia de sistemas de tipos análogos a las lógicas subestructurales donde una o más de las reglas estructurales están ausentes o ...

Los sistemas de tipos subestructurales son una familia de sistemas de tipos análogos a las lógicas subestructurales donde una o más de las reglas estructurales están ausentes o solo se permiten bajo circunstancias controladas. Dichos sistemas pueden restringir el acceso a recursos del sistema , como archivos , bloqueos y memoria, al realizar un seguimiento de los cambios de estado y prohibir estados no válidos. [ 1 ] : 4

Diferentes sistemas de tipos subestructurales

Han surgido varios sistemas de tipos descartando algunas de las reglas estructurales de intercambio, debilitamiento y contracción:

Sistema de tipos ordenados

Los tipos ordenados corresponden a la lógica no conmutativa donde se descartan el intercambio, la contracción y el debilitamiento. Esto se puede usar para modelar la asignación de memoria basada en pila (en contraste con los tipos lineales que se pueden usar para modelar la asignación de memoria basada en montón ). [ 1 ] : 30–31 Sin la propiedad de intercambio, un objeto solo se puede usar cuando está en la parte superior de la pila modelada, después de lo cual se extrae, lo que resulta en que cada variable se use exactamente una vez en el orden en que se introdujo.

Sistemas de tipo lineal

Los tipos lineales corresponden a la lógica lineal y aseguran que los objetos se utilicen exactamente una vez. Esto permite que el sistema libere de forma segura un objeto después de su uso, [ 1 ] : 6 o que diseñe interfaces de software que garanticen que un recurso no se pueda utilizar una vez que se haya cerrado o haya pasado a un estado diferente. [ 2 ]

El lenguaje de programación Clean utiliza tipos de unicidad (una variante de los tipos lineales) para ayudar a soportar la concurrencia, la entrada/salida y la actualización in situ de matrices . [ 1 ] : 43

Los sistemas de tipos lineales permiten referencias , pero no alias . Para garantizar esto, una referencia queda fuera de ámbito tras aparecer en el lado derecho de una asignación , asegurando así que solo exista una referencia a cualquier objeto a la vez. Cabe destacar que pasar una referencia como argumento a una función es una forma de asignación, ya que el parámetro de la función recibirá el valor dentro de la misma; por lo tanto, dicho uso de una referencia también provoca que quede fuera de ámbito.

La propiedad de referencia única hace que los sistemas de tipos lineales sean adecuados como lenguajes de programación para la computación cuántica , ya que refleja el teorema de no clonación de los estados cuánticos. Desde el punto de vista de la teoría de categorías , la no clonación es una afirmación de que no existe ningún functor diagonal que pueda duplicar estados; de manera similar, desde el punto de vista de la lógica combinatoria , no existe ningún K-combinador que pueda destruir estados. Desde el punto de vista del cálculo lambda , una variable xpuede aparecer exactamente una vez en un término. [ 3 ]

Los sistemas de tipos lineales son el lenguaje interno de las categorías monoidales simétricas cerradas , de forma muy similar a como el cálculo lambda simplemente tipado es el lenguaje de las categorías cartesianas cerradas . Más precisamente, se pueden construir functores entre la categoría de sistemas de tipos lineales y la categoría de categorías monoidales simétricas cerradas. [ 4 ]

Sistemas de tipo afín

Los tipos afines son una versión de los tipos lineales que permite descartar (es decir, no usar ) un recurso, lo que corresponde a la lógica afín . Un recurso afín se puede usar como máximo una vez, mientras que uno lineal debe usarse exactamente una vez.

Sistema de tipos pertinente

Los tipos relevantes corresponden a la lógica relevante que permite el intercambio y la contracción, pero no el debilitamiento, lo que se traduce en que cada variable se utilice al menos una vez.

La interpretación de los recursos

La nomenclatura que ofrecen los sistemas de tipos subestructurales es útil para caracterizar los aspectos de gestión de recursos de un lenguaje. La gestión de recursos es el aspecto de la seguridad del lenguaje que se ocupa de asegurar que cada recurso asignado se libere exactamente una vez. Por lo tanto, la interpretación de recursos solo se ocupa de los usos que transfieren la propiedad ( movimiento) , donde la propiedad es la responsabilidad de liberar el recurso.

Los usos que no transfieren la propiedad ( el préstamo ) no entran dentro del alcance de esta interpretación, pero la semántica del ciclo de vida restringe aún más estos usos a un punto intermedio entre la asignación y la desasignación.

tipos afines a los recursos

Según la interpretación de recursos, un tipo afín no puede gastarse más de una vez.

Como ejemplo, la misma variante de la máquina expendedora de Hoare se puede expresar en inglés, en lógica y en Rust :

En este ejemplo, que Coin sea un tipo afín (lo cual es cierto a menos que implemente el rasgo Copy ) significa que intentar gastar la misma moneda dos veces es un programa inválido que el compilador tiene derecho a rechazar:

let coin = Coin {}; let candy = buy_candy ( coin ); // La vida útil de la variable coin termina aquí. let drink = buy_drink ( coin ); // Error de compilación: Uso de una variable movida que no posee el rasgo Copy.

En otras palabras, un sistema de tipos afines puede expresar el patrón typestate : las funciones pueden consumir y devolver un objeto envuelto en diferentes tipos, actuando como transiciones de estado en una máquina de estados que almacena su estado como un tipo en el contexto del llamador (un typestate) . Una API puede aprovechar esto para garantizar estáticamente que sus funciones se llamen en el orden correcto.

Sin embargo, esto no significa que una variable no pueda utilizarse sin consumirse:

// Esta función simplemente toma prestada una moneda: el signo & significa tomar prestada. fn validate ( _ : & Coin ) -> Result < (), () > { Ok (()) }// La misma variable de moneda se puede usar infinitas veces // siempre que no se mueva. let coin = Coin {}; loop { validate ( & coin ) ? ; }

Lo que Rust no puede expresar es un tipo de moneda que no pueda salirse del ámbito; para eso se necesitaría un tipo lineal.

Tipos lineales de recursos

Según la interpretación de recursos, un tipo lineal no solo puede moverse, como un tipo afín, sino que debe moverse; salir del ámbito de aplicación constituye un programa inválido.

{ // Debe transmitirse, no descartarse. let token = HotPotato {};// Supongamos que no todas las ramas lo eliminan: si ! cola . está_llena () { cola . empujar ( token ); }// Error de compilación: Se está reteniendo un objeto que no se puede soltar cuando finaliza el ámbito. }

Una ventaja de los tipos lineales es que los destructores se convierten en funciones regulares que pueden aceptar argumentos, fallar, etc. [ 5 ] Esto puede, por ejemplo, evitar la necesidad de mantener un estado que solo se utiliza para la destrucción. Una ventaja general de pasar explícitamente las dependencias de las funciones es que el orden de las llamadas a funciones (orden de destrucción) se vuelve estáticamente verificable en términos de la duración de los argumentos. En comparación con las referencias internas, esto no requiere anotaciones de duración como en Rust.

Al igual que con la gestión manual de recursos, un problema práctico es que cualquier retorno anticipado , como es típico en el manejo de errores, debe lograr la misma limpieza. Esto se vuelve pedante en lenguajes que tienen desenrollado de pila , donde cada llamada a función es un retorno anticipado potencial. Sin embargo, como analogía cercana, la semántica de las llamadas a destructores insertadas implícitamente se puede restaurar con llamadas a funciones diferidas. [ 6 ]

Tipos normales de recursos

Según la interpretación de recursos, un tipo normal no restringe la cantidad de veces que se puede mover una variable. C++ (específicamente la semántica de movimiento no destructivo) entra en esta categoría.

auto coin = std :: unique_ptr <Coin> ( ); auto candy = buy_candy ( std :: move ( coin ) ); auto drink = buy_drink ( std :: move ( coin )); // Esto es C++ válido.

Lenguajes de programación

Los siguientes lenguajes de programación admiten tipos lineales o afines :

Véase también

Notas

  1. La explicación de los sistemas de tipos afines se entiende mejor si se reformula como "cada ocurrencia de una variable se usa como máximo una vez".
  2. Cada variable puede usarse arbitrariamente.

Referencias

  1. 1 2 3 4 Walker, David (2002). «Sistemas de tipos subestructurales». En Pierce, Benjamin C. (ed.). Temas avanzados en tipos y lenguajes de programación (PDF) . MIT Press. págs. 3–43 . ISBN  0-262-16228-8.
  2. Bernardy, Jean-Philippe; Boespflug, Mathieu; Newton, Ryan R; Peyton Jones, Simon ; Spiwack, Arnaud (2017). "Linear Haskell: practical linearity in a higher-order polymorphic language" . Proceedings of the ACM on Programming Languages . 2 : 1–29 . arXiv : 1710.09756 . doi : 10.1145/3158093 . S2CID 9019395 . 
  3. Baez, John C.; Stay, Mike (2010). "Física, topología, lógica y computación: una piedra Rosetta". En Springer (ed.). Nuevas estructuras para la física (PDF) . págs. 95–174 . 
  4. Ambler, S. (1991). Lógica de primer orden en categorías cerradas monoidales simétricas (Tesis doctoral). Universidad de Edimburgo.
  5. "La visión de Vale" . Consultado el 6 de diciembre de 2023. RAII superior, una forma de tipado lineal que permite destructores con parámetros y retornos.
  6. "Go by Example: Defer" . Consultado el 5 de diciembre de 2023. Defer se utiliza para asegurar que una llamada a una función se ejecute más tarde en la ejecución de un programa, generalmente con fines de limpieza. Defer se usa a menudo donde, por ejemplo, se usarían ensure y finally en otros lenguajes.
  7. "6.4.19. Tipos lineales — Guía del usuario del compilador Glasgow Haskell 9.7.20230513" . ghc.gitlab.haskell.org . Consultado el 14 de mayo de 2023 .
  8. Hudson @twostraws, Paul. "Estructuras y enumeraciones no copiables: disponibles desde Swift 5.9" . Hacking with Swift .