Question

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

data MidiMessage = MidiMessage !Int !MidiMessage
Était-ce utile?

La solution

Il est une déclaration de rigueur. En gros, cela signifie qu'il doit être évalué à ce qu'on appelle « faible forme normale de la tête » lorsque la valeur de la structure de données 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))

Le ci-dessus f fonction lors de son évaluation, retournera un « thunk »: c'est le code à exécuter pour déterminer sa valeur. À ce moment-là, un Foo n'existe même pas encore, juste le code.

Mais quelqu'un à un moment donné peut essayer de regarder à l'intérieur, probablement par une correspondance de motif:

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

Cela va exécuter du code assez 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 testons, nous devons évaluer tout le chemin à 4, où nous nous rendons compte qu'il ne correspond pas.

La seconde n'a pas besoin d'être évalué, parce que nous ne sommes pas le tester. Ainsi, plutôt que 6 étant stocké dans cet emplacement de mémoire, nous allons stocker le code pour une éventuelle évaluation ultérieure, (3+3). Cela va se transformer en un 6 que si quelqu'un regarde.

Le troisième paramètre, cependant, a une ! en face d'elle, de manière strictement évaluée. (4+4) est exécutée, et 8 est stocké dans cet emplacement de mémoire

Le quatrième paramètre est également strictement évalué. Mais voici où il devient un peu délicat: nous évaluons pas complètement, mais seulement à faible forme normale de la tête. Cela signifie que nous comprendre que ce soit Nothing ou quelque chose de Just, et le magasin, mais nous allons pas plus loin. Cela signifie que nous stockons pas Just 10 mais en fait Just (5+5), laissant l'intérieur thunk non évaluée. Il est important de savoir, mais je pense que toutes les implications de cette vont plutôt au-delà de la portée de cette question.

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

f x !y = x*y

f (1+1) (2+2) renverra le (1+1)*4 thunk.

Autres conseils

Une façon simple de voir la différence entre les arguments du constructeur stricts et non strictes est de savoir comment ils se comportent quand ils ne sont pas définies. Compte tenu de

data Foo = Foo Int !Int

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

Étant donné que l'argument non strict est pas évalué par second, en passant undefined ne pose pas de problème:

> second (Foo undefined 1)
1

Mais l'argument stricte ne peut pas être undefined, même si nous ne pas utiliser la valeur:

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

Je crois qu'il est une annotation rigueur.

Haskell est un pur et paresseux langage fonctionnel, mais parfois les frais généraux de lazyness peut être trop ou gaspillage. Donc, pour faire face à cela, vous pouvez demander au compilateur d'évaluer pleinement les arguments à une fonction au lieu de l'analyse syntaxique thunks autour.

Il y a plus d'informations sur cette page. Performance / Sévérité

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top