haskell functional-programming tuples ghc comma

Haskell tuple constructor(GHC) y la separación entre un lenguaje y su implementación



functional-programming tuples (1)

Haskell voló mi mente una vez más cuando me di cuenta de que

(x,y)

Es solo azúcar sintáctico para

(,) x y

Naturalmente, quería extender esto a tuplas más grandes. Pero

(,) x ((,) y z)

Me dio

(x,(y,z))

Que no era lo que estaba buscando. En un capricho, lo intenté

(,,) x y z

Y funcionó, dando exactamente lo que quería:

(x,y,z)

Esto planteó la pregunta: ¿Hasta dónde puede usted llevarlo? Para mi asombro, parecía no haber límite. Todos los siguientes son operadores válidos:

(,) (,,) (,,,) (,,,,) --etc (,,,,,,,,,,,,,,) (,,,,,,,,,,,,,,,) --etc (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) --etc

Este comportamiento es sorprendente y me lleva a mi pregunta real: ¿es algo que se puede emular en mis propias funciones? ¿O es solo una característica específica de GHC del operador de tupla? Estoy pensando que es lo último ya que he leído la especificación haskell98 y iirc dice que las implementaciones solo tienen que definir el operador tuple para hasta 15 elementos. Mientras que GHC se ha ido por las ramas y le permite hacerlo hasta límites arbitrarios.

Entonces, ¿sería posible definir esta familia de operadores / funciones dentro de la propia implementación de haskell, usando nada más que el sistema de tipo y las características del lenguaje existente (declaraciones, firmas de tipo, definiciones de funciones, etc.)? Y si es así, ¿cómo? ¿O es imposible y en su lugar debe buscar en el compilador para encontrar el marco de apoyo para esta colección de funciones?

Esto lleva a una pregunta aún más general: qué tanto de Haskell es compatible con Haskell, a través de definiciones de tipos y funciones, declaraciones, etc. y cuánto es compatible con el compilador / implementación? (Soy consciente de que GHC fue escrito en Haskell, que no responde la pregunta)

Es decir, si abandonara las bibliotecas estándar (incluido el preludio) y hiciera todo desde cero en Raw Haskell; ¿sería posible construir una implementación completa que tenga todas las características de GHC, utilizando solo ese conjunto mínimo de características? ¿Cuál es el conjunto mínimo de características de lenguaje que necesita para construir una implementación de haskell usando Haskell? ¿Podré abandonar el preludio y luego reconstruirlo completamente de forma manual desde dentro de GHC? Si abandonas el preludio y nunca importas nada, ¿qué queda para que trabajes?

Puede parecer que estoy haciendo un millón de preguntas, pero en realidad están tratando de hacer lo mismo con diferentes palabras. Dale tu mejor oportunidad SO!


Por desgracia, no hay magia en las tuplas. Aquí está la implementación que GHC usa , y para darle una idea de lo que está sucediendo, aquí está la fuente para la última definición:

data (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__ = (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__

...sí.

Entonces, ¿sería posible definir esta familia de operadores / funciones dentro de la propia implementación de haskell, usando nada más que el sistema de tipo y las características del lenguaje existente (declaraciones, firmas de tipo, definiciones de funciones, etc.)? Y si es así, ¿cómo? ¿O es imposible y en su lugar debe buscar en el compilador para encontrar el marco de apoyo para esta colección de funciones?

No, no hay forma de definir las tuplas de esa manera genérica. El patrón común es puramente sintáctico, nada que pueda hacerse recursivamente en el sistema de tipos o de otra manera. Podrías generar tales definiciones usando Template Haskell, ciertamente, pero igual estarías generando cada una de ellas individualmente con manipulación de cadenas para crear el nombre, sin usar ningún tipo de estructura compartida.

También está la cuestión de que la sintaxis de tupla está incorporada y no es algo que pueda ser imitado, pero eso es un problema aparte. Puede imaginar tipos como:

data Tuple2 a b = Tuple2 a b data Tuple3 a b c = Tuple3 a b c

... etc., que no usan sintaxis especial pero aún no pueden definirse genéricamente por los motivos anteriores.

Esto lleva a una pregunta aún más general: qué tanto de Haskell es compatible con Haskell, a través de definiciones de tipos y funciones, declaraciones, etc. y cuánto es compatible con el compilador / implementación? (Soy consciente de que GHC fue escrito en Haskell, que no responde la pregunta)

Casi todo se define en Haskell. Ciertas cosas tienen una sintaxis especial que no se puede imitar, pero en la mayoría de los casos eso solo se extiende hasta que el compilador presta especial atención a ciertas definiciones. De lo contrario, no hay diferencia entre this :

data [] a = [] | a : [a]

... y cualquier tipo equivalente que se defina a sí mismo.

Es decir, si abandonara las bibliotecas estándar (incluido el preludio) y hiciera todo desde cero en Raw Haskell; ¿sería posible construir una implementación completa que tenga todas las características de GHC, utilizando solo ese conjunto mínimo de características? ¿Cuál es el conjunto mínimo de características de lenguaje que necesita para construir una implementación de haskell usando Haskell? ¿Podré abandonar el preludio y luego reconstruirlo completamente de forma manual desde dentro de GHC? Si abandonas el preludio y nunca importas nada, ¿qué queda para que trabajes?

Puede encontrar esclarecedor leer acerca de las extensiones NoImplicitPrelude y RebindableSyntax de GHC, que le permiten, entre otras cosas, cambiar las definiciones utilizadas para interpretar la notación do , cómo se manejan los literales numéricos, qué hace la sintaxis if then else , etc.

Baste decir que muy, muy poco no se puede volver a implementar. La mayoría de las cosas que no pueden son solo especiales debido a la sintaxis, y podrían ser reemplazadas por elementos equivalentes (como listas y tuplas, arriba).

Al final hay un conjunto limitado de cosas que tienen un comportamiento muy especial -el tipo de IO es un ejemplo obvio- que no puedes reemplazar en absoluto, porque están enganchados directamente en algo en el sistema de tiempo de ejecución que puedes '' t reemplazar.