2017-08-10 1 views
3

Je suis un tutorial on Haskell en ligne. Nous définissons une fonction pour ajouter des vecteurs bidimensionnels, représentés par des paires de nombres de nombres. Ce qui suit est la déclaration de type explicite, qui garantit que les deux entrées sont des vecteurs bidimensionnels. Je comprends pourquoi la définition de fonction suivante utilise la correspondance de modèle: elle décrit les modèles auxquels les données d'entrée doivent se conformer.Haskell Pattern Match Vecteurs

addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2) 

Pourquoi la définition de fonction alternative suivante n'utilise-t-elle pas la correspondance de modèle? (fst) et (snd) sont garantis pour fonctionner, car les entrées sont explicitement déclarées être des tuples de longueur deux.

Quelle est la différence entre les deux définitions de fonctions?

addVectors a b = (fst a + fst b, snd a + snd b) 
+3

Eh bien, c'est juste un style différent de définir la même chose. Quelle est exactement votre question? – leftaroundabout

+1

En guise de conseil général, je recommande d'apprendre à utiliser autant que possible le pattern matching, au moins au niveau débutant.L'alternative avec 'fst, snd' est OK, mais ici sur SO j'ai vu trop de débutants pour utiliser des fonctions dangereuses comme' head, tail, fromJust', qui conduisent souvent à des crashs, quand le pattern matching est beaucoup plus sûr, surtout quand les avertissements sont activés avec '-Wall' (fortement recommandé). – chi

Répondre

7

Ils diffèrent par leur rigueur. Supposons que nous rebaptiser eux

> let addVectorsStrict (x1, y1) (x2, y2) = (x1 + x2, y1 + y2) 
> let addVectorsLazy a b = (fst a + fst b, snd a + snd b) 

addVectorsStrict undefined undefined est undefined -la correspondance de motif est réalisé dès que le constructeur (,) externe du résultat est exigé:

> case addVectorsStrict (error "A") (error "B") of (_, _) ->() 
*** Exception: A 

Mais addVectorsLazy undefined undefined est (undefined, undefined) -le pattern matching est différé jusqu'à ce que l'un des éléments du résultat soit demandé.

> case addVectorsLazy (error "A") (error "B") of (_, _) ->() 
() 

Fondamentalement, addVectorsLazy retourne toujours un tuple, où les éléments peuvent être évaluées. addVectorsStrict peut ne pas retourner. Vous pouvez également obtenir l'effet de addVectorsLazy en utilisant une correspondance de motif paresseux:

> let addVectorsAlsoLazy ~(x1, y1) ~(x2, y2) = (x1 + x2, y1 + y2) 
> case addVectorsAlsoLazy (error "A") (error "B") of (_, _) ->() 
() 

Pour obtenir une meilleure compréhension de l'ordre d'évaluation, vous pouvez l'observer à l'aide Debug.Trace.trace:

addVectors 
    (trace "first tuple evaluated" 
    (trace "x1 evaluated" 1, trace "y1 evaluated" 2)) 
    (trace "second tuple evaluated" 
    (trace "x2 evaluated" 3, trace "y2 evaluated" 4)) 

La chose fondamentale à retenir au sujet L'évaluation dans Haskell est qu'elle est conduite par la correspondance de modèle en utilisant case et les équations de fonction (qui vont de case).

Il n'a pas beaucoup d'importance dans ce cas, mais vous pouvez écrire vos fonctions paresseusement pour éviter l'évaluation des calculs coûteux si leurs résultats ne sont jamais nécessaires ou strictement pour éviter la surcharge de thunks si vous connaissez un résultat sera toujours être nécessaire.

En général, il est une bonne idée de faire les champs de vos structures de données stricte à moins que vous en avez besoin d'être paresseux et faire vos fonctions paresseux à moins que vous devez être stricte. Ici vous pouvez faire un type de paire strict pour représenter vos vecteurs:

data Vector a = Vector !a !a 
+1

Ceci est vrai, mais probablement beaucoup trop subtile pour être utile à OP ou à quiconque se pose sur cette question de Google. – amalloy

+0

Merci d'avoir compris la question - je ne l'ai pas bien exprimé parce que je ne connaissais pas Haskell! Peut-être que je devrais suivre le [tutoriel officiel] (https://www.haskell.org/tutorial/patterns.html) à la place. –