我是初学者是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))]
答案 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)