2017-10-07 7 views
2

Je suis nouveau à Haskell il peut être évident, mais je l'ai fait Prolog longuement donc je suis perplexe sur celui-ci ...Haskell tuple ne correspond pas à l'argument de la fonction

Lorsque vous utilisez GHCi, j'ai créé la fonction suivante (1):

Prelude> let find k t = head [v | (k',v) <- t, k == k'] -- Definiton of find 
find :: Eq a1 => a1 -> [(a1, a)] -> a 

Prelude> find 2 [(1,11),(2,22)] -- Invocation of find 
22 

Ce qui est attendu. J'ai ensuite essayé d'enlever le k » de la définition:

Prelude> let find2 k t = head [v | (k,v) <- t] 
find2 :: t -> [(t1, a)] -> a 

Prelude> find2 2 [(1,11),(2,22)] 
11 

j'étais alors très surpris de voir la valeur 2 fait en correspondance avec 1. Juste pour être sûr que je n'espérais pas l'impossible, j'essaie également les éléments suivants pour confirme que la correspondance partielle est possible dans Haskell, qui ressemble il est en fait le cas:

Prelude> head [v | (2,v) <- [(1,11),(2,22)]] 
22 

J'ai aussi remarqué une différence dans les déclarations de fonction. J'ai ajouté les informations requises afin que les deux déclarations pour find et find2 se ressemblent exactement. Mais le résultat est encore cassé (2,_) matchnig (1,11):

Prelude> let find2 :: Eq a1 => a1 -> [(a1, a)] -> a; find2 k t = head [v | (k,v) <- t] 
find2 :: Eq a1 => a1 -> [(a1, a)] -> a 

Prelude> find2 2 [(1,11),(2,22)] 
11 

Comment 2 une correspondance des 1 par tout moyen?

(1) La fonction ci-dessus provient de l'excellent livre "Programmation en Haskell" p.93

+4

En bref, Prolog-t unification , Haskell ne fait que l'appariement. – chi

+4

Conseil pratique ennuyeux: l'utilisation de '-Wall' sera vraiment utile pendant que vous apprenez (ainsi que pour attraper les problèmes en code réel) – jberryman

Répondre

11

Oui, pattern matching Haskell est fondamentalement différent de correspondance de motif Prolog.

Dans Haskell, une variable dans un modèle se réfère à une nouvelle variable qui sera liée par la correspondance, jamais une variable existante qui doit être mise en correspondance. Ainsi, l'expression:

let x = 5 in case (1,2) of (x,y) -> "matched!" -- gives "matched!" 

sera toujours évaluée à "apparié!". En effet, le x en (x,y) obtient fraîchement lié à 1, et non par rapport à la valeur de la « existante », la définition extérieure de x, comme vous pouvez le voir ici:

let x = 5 in case (1,2) of (x,y) -> x  -- gives "1" 

Le comportement est différent pour les constantes numériques:

case (1,2) of (5,y) -> "matched!" -- match fails 

et pour d'autres constructeurs:

case (True,2) of (False,y) -> "match!" -- match fails 

qui ne sont pas "re-bound" mais doit correspondre à la correspondance de modèle pour réussir. C'est l'une des nombreuses raisons pour lesquelles les constructeurs alphanumériques commencent par des lettres majuscules: sinon, il serait extrêmement difficile de déterminer si un modèle implique une correspondance avec un constructeur existant ou une reliaison avec une nouvelle variable.

Cela vaut pour motif correspond dans un contexte, que ce soit des expressions de cas comme ci-dessus ou des définitions de fonctions comme ceci:

let x = 5 
f x = "hi"  -- defines `f` for any `x`, not just `f 5` 

ou liste compréhensions comme votre exemple.Dans l'expression:

[v | (k,v) <- [(1,2),(3,4)]] -- gives [(1,2),(3,4)] 

les variables k et v sera toujours frais, donc se lier à l'un des tuples malgré les extérieurs, les définitions existantes de k ou v. Si vous activez les avertissements avec -Wall (plus précisément -Wname-shadowing), cela vous alertera de la liaison ombrée. Si vous remplacez k avec une constante (ou tout autre constructeur), il se comporte différemment:

[v | (3,v) <- [(1,2),(3,4)]] -- only gives [(3,4)] 

Vous ne pouvez pas l'aimer, mais c'est juste la façon dont fonctionne Haskell.

+0

" sinon, il serait extrêmement difficile de déterminer si "-> Meh, c'est juste la vérification de la portée . La mise en évidence de la syntaxe Scope-aware peut gérer cela très bien (voir Agda par exemple) – gallais

0

Merci pour votre aide! Après quelques recherches, j'ai également trouvé cette réponse utile: How can I re-assign a variable in a function in Haskell?

Une nouvelle variable ayant le même nom est créée qui ombrage la précédente. Mais la première variable continue d'exister et, dans certains cas, être toujours accessible ...

donc en effet ce qui est loin de Prolog et oui le drapeau suivant est d'une aide précieuse:

Prelude> :set -fwarn-name-shadowing