2014-07-09 4 views
3

Je commence à programmer avec haskell. Le programme que je développe résume simplement le total d'une liste avec deux elementes, par exemple:Impossible de trouver le type attendu `[([Char], a0)] 'avec le type actuel` ([Char], t0)' Haskell

[("book",10),("cookies",2),("icecream",5)] 

Cela devrait retourner « 17 ». Ici, je mon code:

total [] = [] 
total ([("c",e)]:y) = total y ++ [e] 

Mais en cours d'exécution en GHCi il me donne cette erreur:

<interactive>:80:8: 
    Couldn't match expected type `[([Char], a0)]' 
       with actual type `([Char], t0)' 
    In the expression: ("livro", 10) 
    In the first argument of `total', namely 
     `[("livro", 10), ("bolachas", 2), ("gelado", 5)]' 
    In the expression: 
     total [("livro", 10), ("bolachas", 2), ("gelado", 5)] 

<interactive>:80:21: 
    Couldn't match expected type `[([Char], a0)]' 
       with actual type `([Char], t1)' 
    In the expression: ("bolachas", 2) 
    In the first argument of `total', namely 
     `[("livro", 10), ("bolachas", 2), ("gelado", 5)]' 
    In the expression: 
     total [("livro", 10), ("bolachas", 2), ("gelado", 5)] 

<interactive>:80:36: 
    Couldn't match expected type `[([Char], a0)]' 
       with actual type `([Char], t2)' 
    In the expression: ("gelado", 5) 
    In the first argument of `total', namely 
     `[("livro", 10), ("bolachas", 2), ("gelado", 5)]' 
    In the expression: 
     total [("livro", 10), ("bolachas", 2), ("gelado", 5)] 

Ceci est probablement très simple, mais en tant que débutant, je n'a pas été en mesure de résoudre ce problème.

Répondre

6

Dans la ligne:

total ([("c",e)]:y) = total y ++ [e] 

le ([("c",e)]:y) ne fait pas ce que vous voulez. Il correspond à une liste non vide dans laquelle le premier élément est également une liste (à cause du [...]) et dans lequel cette sous-liste a exactement un élément, qui est une paire dont le premier élément est égal à "c". Afin de correspondre à ce que vous voulez, vous devez écrire:

total ((c,e):y) = total y ++ [e] 

Cependant, cela ne peut toujours pas faire ce que vous voulez, car il construit une liste de tous les e valeurs de la liste d'entrée. Pour les résumer ensemble, vous devez faire:

total [] = 0 
total ((c,e):y) = total y + e 
+0

Merci, ça marche maintenant (: – magamig

4

En plus de ce @jwodder dit, notez qu'il ya aussi une autre façon d'aborder le problème. Au lieu de penser/comment/vous calculeriez la valeur désirée, pensez à/ce que/vous faites: vous prenez le second élément de chaque élément de la liste, puis vous additionnez ces éléments. Vous pouvez donc commencer par écrire deux fonctions, l'une qui prend une liste de tuples donnant une liste de tous les deuxièmes éléments, et l'autre qui calcule la somme d'une liste de nombres donnée. Un bon départ est de venir avec les signatures de type mais définissant les fonctions d'évaluer à undefined:

-- Takes a list of tuples and returns all the second elements 
getSecondElements :: [(String, Int)] -> [Int] 
getSecondElements someList = undefined 

-- Computes the sum of a given list of integers 
sumOfIntList :: [Int] -> Int 
sumOfIntList someInts = undefined 

En utilisant ces derniers, vous définir la fonction est simple:

total myList = sumOfIntList (getSecondElements myList) 

Vous pouvez exécuter ce par ghci et ça va vérifier, ce qui est un bon signe. Lorsque vous essayez d'utiliser réellement total, vous obtenez une erreur car les deux autres fonctions sont juste undefined. Avant d'y réfléchir et de réfléchir à la façon de les implémenter, il est judicieux de voir s'ils existent déjà. Vous pouvez rechercher Hoogle pour les signatures de type et il va déterrer les fonctions correspondant à cette signature. La signature de getSecondElements ne donne aucun résultat, mais la signature de la seconde donne beaucoup de résultats, et la plupart de ces résultats ne parlent même pas de Int: Hoogle est assez intelligent pour comprendre les fonctions qui traitent de types arbitraires des listes (disons: length ou head) peut également être applicable. Si vous faites défiler la page, vous verrez qu'il existe déjà une fonction sum!Pour la première fonction, vous pouvez répéter le processus (récursivement, si vous voulez): pour obtenir tous les deuxièmes-uplets dans une liste, vous devez d'abord avoir une fonction qui obtient le deuxième élément d'un uplet, comme

getSecondElement :: (String, Int) -> Int 
getSecondElement = undefined 

et une autre fonction qui s'applique à tous les éléments d'une liste. Je vais passer un peu en avant: la fonction standard pour obtenir le deuxième élément d'un 2-tuple est appelée snd, et la fonction de collecte des résultats de l'appel d'une fonction sur tous les éléments d'une liste est appelée map. Essayez d'exécuter

:t map snd 

à ghci pour voir le type de map snd:

map snd :: [(a, b)] -> [b] 

... qui est une version généralisée du type de notre fonction getSecondElements! Donc, les deux pièces manquantes sont map snd et sum, ce qui donne:

-- Takes a list of tuples and returns all the second elements 
getSecondElements :: [(String, Int)] -> [Int] 
getSecondElements someList = map snd someList 

-- Computes the sum of a given list of integers 
sumOfIntList :: [Int] -> Int 
sumOfIntList someInts = sum 

Au lieu d'avoir deux fonctions supplémentaires, vous pouvez également définir total en termes de map snd et sum directement:

total someList = sum (map snd someList) 

... qui peut être raccourci à

total = sum . map snd 

Pas mal, n'est-ce pas?

Questions connexes