如何在Haskell中更新列表中的特定元组?

时间:2017-03-10 14:26:09

标签: list haskell tuples

我是初学者是Haskell而且我正在尝试创建一个可以提高具有特定初始值的人的工资的函数,如下所示:

*Main> giveRaise 'A' 200 [('A',"Al",1000),('B',"Bob",1500)]

哪个会给出答案:

[('A',"Al",1200),('B',"Bob",1500)]

到目前为止,我的代码是这样的,但是当我尝试用n来提高初始'g'时,我一直收到错误:

giveRaise :: Char -> Int -> [(Char, String, Int)] -> [(Char, String, Int)]
giveRaise g n [(g, z, m)]
 = [(g, z, (m + n))]

2 个答案:

答案 0 :(得分:6)

您将修改列表中的任意元素,因此最糟糕的情况是您必须循环。由于 recursion 是在Haskell中循环的方法,因此编写giveRaise一个子句很奇怪。使用递归时,您总是有两种类型的子句:

  • 基础案例:我们找到了这个人,然后给他们加薪;和
  • 一个递归案例:我们目前还没有找到这个人,因此一直在寻找它。

基本情况很简单:

giveRaise pa n ((pb,z,m):tail) | pa == pb = (pb,z,m+n):tail

在Prolog中,您可以在 head unification 中使用相同的变量(在Erlang中,检查相等性)。在Haskell中不允许这样做。在Haskell中,使用 guards (如| pa == pb)来确定这两个人是否相同。

现在还有另一种选择:pa不是pb。在otherwise的情况下,我们执行递归并在列表中进一步搜索,所以:

                               | otherwise = (pb,z,m):giveRaise pa n tail

或者把它们放在一起:

giveRaise pa n ((pb,z,m):tail) | pa == pb = (pb,z,m+n):tail
                               | otherwise = (pb,z,m):giveRaise pa n tail

最后我们必须考虑最后一个案例:如果我们到达列表的末尾并且没有找到该人,该怎么办?我们可以简单地忽略它并返回空列表,如:

giveRaise _ _ [] = []

或者我们可以抛出error

giveRaise _ _ [] = error "Could not give a raise."

所以我们可以实现它:

giveRaise pa n ((pb,z,m):tail) | pa == pb = (pb,z,m+n):tail
                               | otherwise = (pb,z,m):giveRaise pa n tail
giveRaise _ _ [] = error "Could not give a raise."

最后请注意,此功能将仅向具有给定标识符的第一个人进行加注。 并非所有具有该标识符的人。但我假设标识符是唯一的。

答案 1 :(得分:3)

“对列表中的一个元素执行某些事情”与“对列表中的每个元素执行其他”相同,其中其他<当元素是你正在寻找的元素时,/ em> 某些东西,当它不是 。换句话说,将此操作构造为map

是有意义的
giveRaise :: Char -> Int -> [(Char, String, Int)] -> [(Char, String, Int)]
giveRaise x amt = map raise
    where raise (y, n, salary)
            | x == y    = (y, n, salary + amt)
            | otherwise = (y, n, salary)