0

Mon professeur nous a montré ce code aujourd'hui, mais je ne peux pas l'air de comprendre le résultat de celui-ci:OCaml - Pourquoi la fonction ne change-t-elle pas sa sortie?

# let a = 2;; 
val a : int = 2 
# let f = fun x -> fun y -> if x = y then a + 2 else a - 10;; 
val : f 'a -> 'a -> int = <fun> 
# f 1 (2 - 1);; 
- : int = 4 
# let a = 18;; 
val a : int = 18 
# f 1 (2 - 1);; 
- : int = 4 

??? Donc, fondamentalement, je m'attends à voir ce résultat:

- : int = 20 

Pourquoi n'est-ce pas la sortie?

Répondre

7

Il est parce que let a a fait introduire une nouvelle variable avec le même nom, mais la fonction fait toujours référence à celle de son champ d'application - c'est un closure, et la variable qu'il recouvrit est une constante. Il ne recherche pas le nom de la variable dynamiquement dans la portée à partir de laquelle il est appelé.

Vous pouvez obtenir le comportement que vous attendiez en stockant une mutable reference dans la variable que vous pouvez attribuer à:

# let a = ref 2;; 
    let f = fun x -> fun y -> if x = y then !a + 2 else !a - 10;; 
    f 1 (2 - 1);; 
- : int = 4 
# a := 18;; 
    f 1 (2 - 1);; 
- : int = 20 

Cependant, notez que ce qui est généralement souhaité. Les variables doivent être constantes, de sorte que nous puissions discuter de la fonction f en renvoyant toujours 4 ou 8 lorsqu'elle est appelée, au lieu de faire dépendre le résultat de l'endroit et de la date d'attribution de la cellule de référence. Évitez-les où vous le pouvez. Dans cet exemple particulier, on pourrait le faire comme ceci:

let f a x y = 2 + if x = y then 2 else -10 in 
let g = f 2 in 
print_int (g 1 (2-1)); 
let h = f 18 in 
print_int (h 1 (2-1));; 
+1

Ne pas montrer les références aux étudiants, idiot! :-p – PatJ

+1

@PatJ Exactement ce que je pensais :-) Je vais éditer dans un avertissement approprié – Bergi

+0

@PatJ est un imbécile impure pire qu'un imbécile pur dans ce cas? –