41 votes

la fonction de séquenceur et la rigueur

J'ai été me demandais beaucoup, mais je n'ai pas été en mesure de trouver quoi que ce soit.

Lors de l'utilisation de l' seq fonction, comment est-il alors vraiment travailler? Partout, c'est juste expliqué en disant qu' seq a b évalue a, ignore le résultat et les retours b.

Mais que veut vraiment dire? Serait le résultat suivant dans le strict d'évaluation:

foo s t = seq q (bar q t) where
      q = s*t

Ce que je veux dire c'est, est - q strictement évalués avant d'être utilisés en bar? Et la suite être équivalent:

foo s t = seq (s*t) (bar (s*t) t)

Je trouve ça un peu dur d'obtenir des détails sur les fonctionnalités de cette fonction.

34voto

John L Points 20989

Vous n'êtes pas seul. seq est probablement l'un des plus difficiles Haskell fonctions de l'utiliser correctement, pour quelques raisons différentes. Dans votre premier exemple:

foo s t = seq q (bar q t) where
      q = s*t

q est évaluée avant d' bar q t est évaluée. Si bar q t n'est jamais évalué, q ne sera pas non plus. Donc, si vous avez

main = do
    let val = foo 10 20
    return ()

en tant que val n'est jamais utilisé, il ne sera pas évalué. Donc, q ne seront pas évaluées. Si, au contraire, vous avez

main = print (foo 10 20)

le résultat de l' foo 10 20 est évaluée (en print), de sorte que dans foo q est évalué avant le résultat de l' bar.

C'est aussi pourquoi cela ne fonctionne pas:

myseq x = seq x x

Du point de vue sémantique, cela signifie que le premier x sera évalué avant le deuxième x est évaluée. Mais si le second x n'est jamais évalué, le premier n'a pas besoin de l'être. Donc, seq x x est exactement équivalent à x.

Votre deuxième exemple peut ou peut ne pas être la même chose. Ici, l'expression s*t seront évalués avant d' bar's de sortie, mais il ne peut pas être le même s*t comme premier paramètre bar. Si le compilateur effectue commune de la sous-expression de l'élimination, il peut commun-les deux expressions identiques. GHC peut être assez conservateur sur l'endroit où il n'CST bien, vous ne pouvez pas compter sur cela. Si je définis bar q t = q*t il ne effectuer le CST et d'évaluer s*t avant d'utiliser cette valeur dans la barre. Il ne peut pas le faire pour des expressions plus complexes.

Vous pouvez également connaître ce que l'on entend par évaluation stricte. seq évalue le premier argument de la faiblesse de la tête forme normale (WHNF), qui, pour des types de données signifie déballage le constructeur le plus externe. Réfléchissez à ceci:

baz xs y = seq xs (map (*y) xs)

xs doit être une liste, en raison de l' map. Lors de l' seq évalue, il servira essentiellement à transformer le code en

case xs of
  [] -> map (*y) xs
  (_:_) -> map (*y) xs

Cela signifie qu'il permettra de déterminer si la liste est vide ou pas, puis retourner le deuxième argument. Notez qu' aucune des valeurs de la liste sont évalués. Ainsi, vous pouvez faire ceci:

Prelude> seq [undefined] 4
4

mais pas cette

Prelude> seq undefined 5
*** Exception: Prelude.undefined

Quel que soit le type de données que vous utilisez pour l' seqs premier argument, l'évaluation de WHNF va aller assez loin pour comprendre le constructeur et rien de plus. À moins que le type de données possède des composants qui sont marqués comme strict avec un bang modèle. Ensuite, tous les strictes domaines seront également évalués à WHNF.

Edit: (merci à Daniel Wagner pour la suggestion dans les commentaires)

Pour les fonctions, seq permettra d'évaluer l'expression jusqu'à ce que la fonction "a un lambda de montrer", ce qui signifie qu'il est prêt pour l'application. Voici quelques exemples qui pourraient démontrer ce que cela signifie:

-- ok, lambda is outermost
Prelude> seq (\x -> undefined) 'a'
'a'

-- not ok.  Because of the inner seq, `undefined` must be evaluated before
-- the lambda is showing
Prelude> seq (seq undefined (\x -> x)) 'b'
*** Exception: Prelude.undefined

Si vous pensez à un lambda de liaison comme un (built-in) données constructeur, seq sur des fonctions qui est parfaitement cohérent avec l'utilisant sur des données.

Aussi, "lambda de liaison" englobe tous les types de définitions de fonction, qu'il s'agisse d'lambda ou de notation comme une fonction normale.

La Controverse de la section de la HaskellWiki du seq page a un peu de certaines des conséquences de l' seq par rapport aux fonctions.

4voto

gfour Points 653

Vous pouvez penser à de la seq comme:

seq a b = case a of
            _ -> b

Cela permettra d'évaluer l' a -à-tête-forme normale (WHNF) et ensuite continuer avec l'évaluation b.

Edit après augustss commentaire: ce case ... of est le stricte, GHC Core, qui toujours les forces de son argument.

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