【问题标题】:Couldn't match expected type `[([Char], a0)]' with actual type `([Char], t0)' Haskell无法将预期类型 `[([Char], a0)]' 与实际类型 `([Char], t0)' Haskell 匹配
【发布时间】:2014-08-30 21:20:41
【问题描述】:

我开始用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)]

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

【问题讨论】:

    标签: haskell char int ghci


    【解决方案1】:

    行内:

    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
    

    【讨论】:

      【解决方案2】:

      除了@jwodder 所说的之外,请注意还有另一种解决问题的方法。与其考虑 /how/ 你会计算期望的值,不如考虑 /what/ 你做了什么:你获取每个列表项的第二个元素,然后将这些元素相加。

      因此,您可以从编写两个函数开始,一个接受元组列表,生成所有第二个元素的列表,另一个计算给定数字列表的总和。一个好的开始是提出类型签名,但定义要评估为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 足够聪明,可以理解那些函数处理任意类型的列表(例如:length 或 head)也可能适用。如果您向下滚动页面,您会看到现有的sum 函数已经存在!

      对于第一个函数,你可以重复这个过程(递归,如果你喜欢):为了得到一个列表中的所有第二个元组元素,你首先需要一个函数来获取一个元组的第二个元素,比如

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

      和另一个将其应用于列表的所有元素的函数。我先略过一下:获取 2 元组的第二个元素的标准函数称为 snd,而用于收集对列表的所有元素调用函数的结果的函数称为 map。尝试运行

      :t map snd
      

      在ghci中查看map snd的类型:

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

      ...这是我们getSecondElements函数类型的通用版本!所以缺少的两个部分是map snd 和sum,给出:

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

      除了有两个额外的函数,你还可以直接用map snd和sum定义total:

      total someList = sum (map snd someList)
      

      ...可以缩短为

      total = sum . map snd
      

      还不错吧?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-23
        相关资源
        最近更新 更多