无法匹配期望的类型`[([Char],a0)]'实际类型`([Char],t0)'哈斯克尔

时间:2014-07-09 17:54:10

标签: haskell char int ghci

我开始使用haskell进行编程。我正在开发的程序只是将一个列表的总和与两个元素相加,例如:

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

这应该返回“17”。这是我的代码:

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

但是在GHCi中运行时,它给了我这个错误:

<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)]

这可能非常简单,但作为初学者,我无法解决这个问题。

2 个答案:

答案 0 :(得分:6)

在行中:

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

([("c",e)]:y)没有做你想做的事。它匹配一个非空列表,其中第一个元素也是一个列表(因为[...]),并且该子列表中只有一个元素,即第一个元素等于"c"的对。为了匹配你想要的东西,你需要写:

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

然而,这仍然不会做你想要的,因为它构造了输入列表中所有e值的列表。要将它们相加,您需要这样做:

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

答案 1 :(得分:4)

除了@jwodder所说的,还要注意还有另一种解决问题的方法。不要考虑/如何/你将计算所需的值,考虑/你做什么:你采取每个列表项的第二个元素,然后将这些元素加起来。

所以你可以从编写两个函数开始,一个函数获取一个元组列表,产生一个包含所有第二个元素的列表,另一个函数计算给定数字列表的总和。一个好的开始是提出类型签名,但定义要评估为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

使用这些,定义你的功能很简单:

total myList = sumOfIntList (getSecondElements myList)

你可以通过ghci运行它并进行类型检查,这是一个好兆头。当您尝试实际使用total时,会收到错误,因为其他两个函数只是undefined

在你开始思考如何实施它们之前,最好先看看它们是否已经存在。您可以搜索Hoogle类型签名,并搜索与该签名匹配的函数。 getSecondElements的签名不会产生任何点击,但第二个的签名会产生很多点击,而且大多数点击甚至根本不会谈论Int:Hoogle足够聪明,可以理解处理任意类型的列表(例如:lengthhead)的函数也可能适用。如果您向下滚动页面,您会发现现有的sum功能已经存在!

对于第一个函数,您可以重复该过程(如果您愿意,可以递归地):为了获取列表中的所有二元组元素,您首先需要一个函数来获取元组的第二个元素,如

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

和另一个将其应用于列表的所有元素的函数。我稍后跳过:获取2元组的第二个元素的标准函数称为snd,并且用于收集在列表的所有元素上调用函数的结果的函数被调用map。尝试运行

:t map snd

在ghci中查看map snd的类型:

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

...这是我们getSecondElements函数类型的通用版本!所以这两个缺失的部分是map sndsum,它们给出了:

-- 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

您可以直接使用totalmap snd来定义sum,而不是拥有两个额外的功能:

total someList = sum (map snd someList)

......可以缩短为

total = sum . map snd

不错,是吗?