将两个年龄段的人的总余额相加

时间:2012-11-11 17:33:11

标签: haskell

我正在尝试计算在银行内拥有帐户的两个年龄段的人/客户的总余额。我可以让它显示符合要求的人员名单。

这些是构造函数

    type NI = Int
    type Age = Int
    type Balance = Int
    type Person = (NI, Age, Balance)
    type Bank = [Person]

这是银行

    rbs :: Bank
    rbs = [ (1, 73, 1000)
        , (2, 18, -50)
        , (3, 60, 190)
        , (4, 26, 300)
        , (5, 24, 456)
        , (6, 32, 7500)
        , (7, 41, -46)
        , (8, 59, -850)
        , (9, 44, 348)
        , (10, 66, -1000)
        , (11, 37, 20000)
        , (12, 29, -245)
        , (13, 55, 3090)
        ]

这是我递归检查银行的​​代码

        equityA' :: Bank -> (Int, Int) -> Bank
        equityA' ((n,a,b):xs) (0,0) = error "No ages were selected"
        equityA' [] (x,y) = []
        equityA' ((n,a,b):xs) (f, s) = if  (f <= a) && (s >= a) then  (n,a,b) : equityA' xs (f, s) 
                                       else equityA' xs (f, s)

如果我运行equityA'rbs(40,50),输出将是[(7,41,-46),(9,44,348)]

我正在努力做的是打印出那些人的总余额。我有一些代码,但我被困在实际的计算部分。

检查总数的代码。

    equityAge :: Bank -> (Int, Int) -> Int              
    equityAge ((n,a,b):xs) (0,0) = error "No ages were selected"
    equityAge [] (x,y) = 0
    equityAge ((n,a,b):xs) (f, s) = 

如果有任何帮助,我将不胜感激。

2 个答案:

答案 0 :(得分:3)

如果您使用list comprehensions

,这很简单
equityAge :: Bank -> (Int,Int) -> Int
equityAge _ (0,0) = error "No ages were selected"
equityAge [] (x,y) = 0
equityAge x (f,s) = sum [ b | (n,a,b) <-x, f <= a, a <= s]

除此之外,您可以应用Sarah's advice并在原始功能上使用mapsum

equityAge :: Bank -> (Int,Int) -> Int
equityAge _ (0,0) = error "No ages were selected"
equityAge [] (x,y) = 0
equityAge x (f,s) = sum (map(\(_,_,b) -> b) (equityA' x (f,s)))

答案 1 :(得分:1)

我建议这里有三件主要的事情:(a)使用记录类型而不是元组; (b)使用标准效用函数来处理列表和其他标准类型; (c)编写辅助功能,以帮助保持所有功能简短易读。

关于第一个建议:

data Person = Person { ni :: NI, age :: Age, balance :: Balance } deriving (Eq, Show)

现在你不必做任何一个元组模式匹配只是为了得到一个人的年龄;此记录类型声明可免费获取函数age :: Person -> Agebalance :: Person -> Balance

第三条建议的例子:这是一个计算Person是否在两个年龄之间的函数:

betweenAges :: Age -> Age -> Person -> Bool
betweenAges lo hi person = lo <= age person && age person <= hi

现在,使用该辅助功能和标准filter功能,您可以获得两个年龄段之间的所有人:

filter (betweenAges 18 27) rbs

要获得Person列表的余额,您可以使用标准summap函数:

sum (map balance somePersons)

所以完整的解决方案就是这样:

-- Note how much easier to read this is when you use sum, map, filter 
-- and betweenAges!
equityAge :: Age -> Age -> Bank -> Balance
equityAge lo hi bank = sum (map balance (filter (betweenAges lo hi) bank))
    -- This could be its own top-level function if you're going to reuse it
    -- somewhere else, but here I'm putting it in a where declaration assuming
    -- that it's a throwaway.
    where betweenAges lo hi person = lo <= age person && age person <= hi

作为一般规则,努力寻找如何解决你所处理的问题并不富有成效。我认为,更具生产力的策略如下:(a)学习如PreludeData.ListData.Maybe等基本库中的功能解决问题; (b)学习如何自己编写这些实用功能。为什么这样?因为(a)教你如何将问题分解成小的,可重复使用的部分,并且(b)教你理解这些程序中从底部到顶部发生的事情。