Quel type de portée Haskell utilise-t-il?
Question
J'essaie de déterminer si Haskell utilise une portée dynamique ou statique. Je me rends compte que, par exemple, si vous définissez:
let x = 10
puis définissez la fonction
let square x = x*x
Vous avez 2 "x" différents, et cela signifie-t-il que sa portée est dynamique? Si non, quelle portée utilise-t-il et pourquoi?
De plus, les variables Haskell peuvent-elles avoir des alias (un nom différent pour le même emplacement / valeur de mémoire)?
Merci.
La solution
Il y a des erreurs dans vos déclarations ...
- Il n'y a pas de variables mutables dans Haskell mais juste des définitions (ou des variables immuables)
- Un emplacement de mémoire variable est un concept qui n'existe pas dans Haskell
Dans votre exemple, x est pas 10 dans la fonction, il s'agit simplement d'un argument en carré, pouvant prendre n'importe quelle valeur (vous pouvez spécifier le type ultérieurement). cas 10 mais juste dans ce cas.
Voici un exemple d'alias fourni par 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
Autres conseils
Haskell utilise (en termes généraux) exactement la même portée lexicale que la plupart des autres langues.
par exemple.
x = 10
Résultats dans une valeur référencée via x
dans la portée globale, alors que
square x = x * x
aura pour résultat que x
sera étendu de manière lexicale au carré de la fonction. Cela peut aider si vous pensez que la forme ci-dessus est une finesse syntaxique pour:
square = \ x -> x * x
En ce qui concerne votre autre question, je ne suis pas sûr de ce que vous entendez par aliasing
Répondant uniquement à la deuxième partie de la question:
Vous pouvez avoir plusieurs alias pour le même "emplacement de mémoire", mais comme ils sont tous immuables, peu importe la plupart du temps.
Exemple muet:
foo x y = x * y
bar z = foo z z
Lorsque foo
est appelé depuis la x
et y
ont clairement la même valeur. Mais comme vous ne pouvez modifier ni x
ni y
, vous ne le remarquerez même pas.
Comme la première partie de la question a déjà été répondue, voici la deuxième partie:
Je suppose que par aliasing
, vous voulez dire un nom pour un autre
. Comme haskell est un langage fonctionnel et que les fonctions se comportent comme des identifiants normaux, vous pouvez le faire comme ceci:
y = x
qui définirait un alias y
pour la fonction x
. Notez que tout est une fonction. Même si cela ressemble à une "variable" , il s’agit simplement d’une fonction nullary ne prenant aucun argument. Les alias des types se présentent comme suit:
type Function = Double -> Double
qui définirait un alias Fonction
pour le type Double - > Double
Haskell utilise des étendues imbriquées statiques. Ce qui est un peu déroutant par rapport aux autres langages ayant des portées imbriquées statiques est que la portée d'un nom est un bloc qui inclut des tests précédant sa définition . Par exemple
evens = 0 : map (+1) odds
odds = map : (+1) evens
Ici, le nom "cotes" figure dans la définition du mot "même", malgré le fait surprenant que "cotes" n’ait pas encore été défini. (L'exemple définit deux listes infinies de nombres pairs et impairs.)
Une langue morte avec une règle de portée similaire était Modula-3. Mais Haskell est un peu plus délicat en ce sens que vous pouvez essayer de "redéfinir" une variable dans le même périmètre, mais en introduisant simplement une autre équation de récursivité. C’est un piège pour les personnes qui ont appris le ML ou le schéma en premier:
let x = 2 * n
x = x + 1 -- watch out!
Ceci est parfaitement bon ML ou Scheme let *, mais Haskel a une sémantique de schéma letrec, sans restriction aux valeurs lambda. Pas étonnant qu'il s'agisse de choses difficiles!
Dans votre exemple, la définition globale de x est ombrée par la définition locale de x. Dans Haskell, la portée d'une variable est déterminée par une lecture statique du code source - c'est ce qu'on appelle la portée lexicale, mais peut obtenir quelque chose de similaire à la portée dynamique avec des paramètres implicites (mais cela peut entraîner un comportement inattendu (j'ai lu; jamais essayé moi-même)).
Pour résumer les autres réponses avec concision:
- portée lexicale
- aliasing est aussi simple que
x = 1; y = x
, mais cela n’a généralement aucune importance, car les choses sont immuables.
La syntaxe let
que vous utilisez dans votre exemple semble se trouver à l'invite interactive ghci >
. Tout en mode interactif se produit au sein de la monade d’OI, de sorte que les choses peuvent sembler plus modifiables que la normale.
Eh bien, comme je pense que les gens l’ont déjà dit, Haskell n’a aucune variable comme dans la plupart des autres langues, elle n’a que des expressions. Dans votre exemple, let x = 10
x est une expression évaluée toujours à 10. Vous ne pouvez pas modifier la valeur de x ultérieurement, bien que vous puissiez utiliser les règles de portée pour le masquer en définissant x être une autre expression.
Oui, Haskell a des alias. Essayez ce petit programme:
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