haskell scope alias

¿Qué tipo de alcance usa Haskell?



scope alias (9)

Estoy tratando de averiguar si Haskell usa el alcance dinámico o estático. Me doy cuenta de eso, por ejemplo, si defines:

let x = 10

luego define la función

let square x = x*x

Tienes 2 "x" diferentes, ¿y eso significa que tiene un alcance dinámico? Si no, ¿qué alcance utiliza y por qué?

Además, ¿las variables Haskell pueden tener alias (un nombre diferente para la misma ubicación / valor de memoria)?

Gracias.


Como la primera parte de la pregunta ya fue respondida por otros, esta es la segunda parte:

Supongo que aliasing significa one name for another . Como haskell es un lenguaje funcional, y las funciones se comportan como identificadores normales en cualquier caso, puedes hacerlo así:

y = x

que definiría un alias y para la función x . Tenga en cuenta que todo es una función. Incluso si parece una "variable" , es solo una función nulary sin argumentos. Los alias para los tipos se ven así:

type Function = Double -> Double

que definiría una Function alias para el tipo Double -> Double


Haskell usa (en términos generales) exactamente el mismo alcance léxico que la mayoría de los otros idiomas.

p.ej.

x = 10

Resultados en un valor al que se hace referencia a través de x en el ámbito global, mientras que

square x = x * x

dará como resultado que x tenga un alcance léxico para el cuadrado de función. Puede ser útil si considera que la forma anterior es una sutileza sintáctica para:

square = / x -> x * x

En cuanto a su otra pregunta, no estoy seguro de lo que quiere decir con aliasing


Respondiendo solo la segunda parte de la pregunta:

Puede tener varios alias para la misma "ubicación de memoria", pero como todos son inmutables, no importa la mayor parte del tiempo.

Tonto ejemplo:

foo x y = x * y bar z = foo z z

Cuando dentro de foo llama desde la bar , tanto x como y son claramente del mismo valor. Pero como no puedes modificar ni x ni y , ni siquiera lo notarás.


Para resumir las otras respuestas de manera concisa:

  1. alcance léxico
  2. aliasing es tan fácil como x = 1; y = x x = 1; y = x pero usualmente no importa porque las cosas son inmutables.

La sintaxis de let que usa en su ejemplo parece que está en el indicador ghci> interactivo. Todo en el modo interactivo ocurre dentro de la mónada IO, por lo que las cosas pueden parecer más mutables allí de lo normal.


Bueno, como creo que la gente ya dijo, Haskell no tiene ninguna variable como se encuentra en la mayoría de los otros idiomas, solo tiene expresiones. En su ejemplo, let x = 10 x es una expresión que siempre se evalúa como 10. En realidad, no puede cambiar el valor de x más tarde, aunque puede usar las reglas de scoping para ocultarlo definiendo x como otra expresión.


Haskell usa ámbitos anidados estáticos. Lo que es un poco confuso en comparación con otros lenguajes que tienen alcances anidados estáticos es que el alcance de un nombre es un bloque que incluye pruebas que preceden a su definición . Por ejemplo

evens = 0 : map (+1) odds odds = map : (+1) evens

aquí el nombre ''odds'' está en el alcance en la definición de ''evens'', a pesar del sorprendente hecho de que ''odds'' aún no se ha definido. (El ejemplo define dos listas infinitas de números pares e impares).

Una lengua muerta con una regla de alcance similar era Modula-3. Pero Haskell es un poco más complicado en el sentido de que puede intentar ''redefinir'' una variable dentro del mismo ámbito, pero en su lugar, simplemente introduce otra ecuación de recursión. Este es un escollo para las personas que aprendieron ML o Scheme primero:

let x = 2 * n x = x + 1 -- watch out!

Esto es perfectamente válido. ML o Scheme let *, pero Haskel tiene una semántica de esquema letrec, sin la restricción de valores lambda. ¡No es de extrañar que esto sea algo complicado!


Sí, Haskell tiene alias. Pruebe este pequeño programa:

import Data.IORef main :: IO () main = do x <- newIORef 0 -- write 0 into x readIORef x >>= print -- x contains 0 let y = x readIORef y >>= print -- y contains 0 writeIORef x 42 -- write 42 into x readIORef y >>= print -- y contains 42


En su ejemplo, la definición global de x está sombreada por la definición local de x. En Haskell, el alcance de una variable está determinado por una lectura estática del código fuente; esto se llama ámbito léxico, pero puede obtener algo similar al alcance dinámico con parámetros implícitos (pero eso puede conducir a un comportamiento inesperado (lo he leído; probé yo mismo)).


Hay algunas cosas mal en sus declaraciones ...

  • No hay variables mutables en Haskell solo definiciones (o variables inmutables)
  • Una ubicación de memoria variable es un concepto que no existe en Haskell

En su ejemplo, x no es 10 en la función es solo un argumento para cuadrado, que puede tomar cualquier valor (puede especificar el tipo más adelante) en este caso 10, pero solo en este caso.

Aquí hay un ejemplo de alias proporcionados por Curt Sampson :

import Data.IORef main :: IO () main = do x <- newIORef 0 -- write 0 into x readIORef x >>= print -- x contains 0 let y = x readIORef y >>= print -- y contains 0 writeIORef x 42 -- write 42 into x readIORef y >>= print -- y contains 42