2016-07-11 52 views
1

我一直在研究Haskell一个星期,并试图自己写一些真实世界的函数。我的目标是根据各自的硬币和所述硬币的数量来表达金额。但我不确定当我编写函数时是否在“功能上”思考。示例代码如下所示;用变化来表达资金总额

changes = [1,2,5,10,25,50] 

makechanges n cs = if n `div` (last cs) > 0 
        then (coin_amount, last cs) : makechanges (n - coin_amount * current_coin) (init cs) 
        else makechanges n (init cs) 
        where coin_amount = n `div` (last cs) 
         current_coin = last cs 

示例输出

makechanges 126 changes 
[(50,2),(25,1),(1,1)] 

是否有写预期功能更FP的方式?我觉得这个功能只是命令式功能的转换,事先要感谢。

+3

一个明显的改善将是扭转'changes'列表。列表是不对称的,'last'和'init'很贵,'head'和'tail'很便宜。 –

+0

感谢这个建议,我完全忘记了haskell列表的链表结构。 –

+1

我的风格建议是忘记部分函数'head,tail',并且简单地坚持模式匹配。我也是第二。扭转名单的建议:从较大的硬币开始。 – chi

回答

1

甲左折叠的解决办法是:

change :: (Foldable t, Integral a) => a -> t a -> [(a, a)] 
change total coin = foldl go (const []) coin total 
    where 
    go run c x = if x < c then run x else (c, x `div` c): run (x `mod` c) 

然后:

\> change 126 [1, 2, 5, 10, 25, 50] 
[(50,2),(25,1),(1,1)] 
+0

因为我已经工作了一周(而不是整整一整天的时间),可折叠的,现在去跑步并没有响铃。但是,我当然会继续研究和重新审视这个解决方案。 –