286 votes

Que signifie le point d'exclamation dans une déclaration Haskell?

Je suis tombé sur la définition suivante que j'essaie d'apprendre Haskell en utilisant un vrai projet pour le conduire. Je ne comprends pas ce que signifie le point d'exclamation devant chaque argument et mes livres ne semblent pas le mentionner.

 data MidiMessage = MidiMessage !Int !MidiMessage
 

342voto

Curt Sampson Points 10866

C'est une rigueur déclaration. Fondamentalement, cela signifie qu'il doit être évalué à ce que l'on appelle "la faiblesse de la normale de la forme de la tête" quand la structure de données valeur est créée. Regardons un exemple, afin que nous puissions voir exactement ce que cela signifie:

data Foo = Foo Int Int !Int !(Maybe Int)

f = Foo (2+2) (3+3) (4+4) (Just (5+5))

La fonction f - dessus, lors de l'évaluation, sera de retour un "thunk": c'est le code à exécuter à la figure de sa valeur. À ce stade, une Foo n'existe même pas encore, juste le code.

Mais à un certain moment, quelqu'un peut essayer de regarder à l'intérieur, probablement par le biais d'une mise en correspondance du modèle:

case f of
     Foo 0 _ _ _ -> "first arg is zero"
     _           -> "first arge is something else"

Cela va exécuter le code nécessaire pour faire ce dont il a besoin, et pas plus. Donc, il va créer un Foo avec quatre paramètres (parce que vous ne pouvez pas regarder à l'intérieur sans l'existant). La première, puisque nous sommes en train de tester cela, nous avons besoin d'évaluer tout le chemin de 4, où nous nous rendons compte qu'il ne correspond pas.

La deuxième n'a pas besoin d'être évaluée, car nous ne sommes pas le tester. Ainsi, plutôt que d' 6 d'être stockée dans cet emplacement de la mémoire, nous allons stocker le code pour l'évaluation, (3+3). Qui va se transformer en une 6 que si quelqu'un la regarde.

Le troisième paramètre, cependant, a un ! , en face de lui, donc est strictement évaluée: (4+4) est exécutée, et 8 est stocké dans cet emplacement de la mémoire.

Le quatrième paramètre est également strictement évalués. Mais là où ça devient un peu délicat: nous évaluons pas entièrement, mais seulement à la faiblesse de la normale de la forme de la tête. Cela signifie que nous avons à voir si c'est Nothing ou Just quelque chose, et de les stocker, mais nous n'allons pas plus loin. Cela signifie que nous ne pas stocker Just 10 mais en réalité, Just (5+5), laissant le thunk à l'intérieur non évaluée. C'est important de le savoir, mais je pense que toutes les implications de cette allez plutôt au-delà de la portée de cette question.

Vous pouvez annoter les arguments de la fonction, de la même manière, si vous activez l' BangPatterns extension du langage:

f x !y = x*y

f (1+1) (2+2) sera de retour le thunk (1+1)*4.

107voto

Chris Conway Points 24671

Un moyen simple de voir la différence entre les arguments constructeurs strict et non strict est de savoir comment ils se comportent lorsqu'ils ne sont pas définis. Donné

 data Foo = Foo Int !Int

first (Foo x _) = x
second (Foo _ y) = y
 

Puisque l'argument non strict n'est pas évalué par second , le passage dans undefined ne cause pas de problème:

 > second (Foo undefined 1)
1
 

Mais l'argument strict ne peut pas être undefined , même si nous n'utilisons pas la valeur:

 > first (Foo 1 undefined)
*** Exception: Prelude.undefined
 

29voto

Chris Vest Points 5622

Je crois que c'est une annotation de rigueur.

Haskell est un langage fonctionnel pur et paresseux , mais parfois les frais généraux de la paresse peuvent être trop ou gaspillage. Donc, pour faire face à cela, vous pouvez demander au compilateur d'évaluer complètement les arguments d'une fonction au lieu d'analyser les thunks.

Il y a plus d'informations sur cette page: Performance / Strictness .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X