我的方法是使用命令式代码尝试问题,然后使用惯用功能代码再次尝试相同的问题。
这是我目前正在解决的问题:
更改退货计划 - 用户输入费用,然后输入金额。该计划将找出变化所需的季度,硬币,镍币,硬币的数量变化。
这是我天真(迫切)的解决方案:
let cost = 1.10m
let amountGiven = 2.00m
let mutable change = amountGiven - cost
while change <> 0m do
if change >= 0.25m then
Console.WriteLine "quater"
change <- change - 0.25m
else if change >= 0.10m then
Console.WriteLine "dime"
change <- change - 0.10m
else if change >= 0.05m then
Console.WriteLine "nickel"
change <- change - 0.05m
else if change >= 0.01m then
Console.WriteLine "penny"
change <- change - 0.01m
如何使用功能结构编写此代码(即没有mutable
)?
答案 0 :(得分:5)
在这种情况下,最简单的方法是将可变变量移动到函数参数中并使用递归(while
只是对递归的暂停检查):
let cost = 1.10m
let amountGiven = 2.00m
let rec giveChange change =
if change > 0 then
if change >= 0.25m then
Console.WriteLine "quater"
giveChange (change - 0.25m)
else if change >= 0.10m then
Console.WriteLine "dime"
giveChange (change - 0.10m)
else if change >= 0.05m then
Console.WriteLine "nickel"
giveChange (change - 0.05m)
else if change >= 0.01m then
Console.WriteLine "penny"
giveChange (change - 0.01m)
giveChange (amountGiven-cost)
这是明显的翻译
当然,双if
有点过时了:
let rec giveChange change =
if change >= 0.25m then
Console.WriteLine "quater"
giveChange (change - 0.25m)
else if change >= 0.10m then
Console.WriteLine "dime"
giveChange (change - 0.10m)
else if change >= 0.05m then
Console.WriteLine "nickel"
giveChange (change - 0.05m)
else if change >= 0.01m then
Console.WriteLine "penny"
giveChange (change - 0.01m)
当然,许多if
看起来很糟糕 - 让我们用一个列表替换它们:
let coins = ["quarter", 0.25m; "dime", 0.10m; "nickel", 0.05m; "penny", 0.01m]
let rec giveChange change =
match coins |> List.tryFind (fun (_,c) -> change >= c) with
| Some (name,coin) ->
Console.WriteLine name
giveChange (change-coin)
| None -> ()
我认为现在这是一个合理的解决方案。
没有一种情况永远不会发生,因为我们已经在那里获得了一分钱(或者我们希望如此,因为如果某人支付不够而且价值变为负值,我们就会遇到麻烦) - 也许我们应该给一些人更好的暗示:
let coins = ["quarter", 0.25m; "dime", 0.10m; "nickel", 0.05m; "penny", 0.01m]
let rec giveChange change =
if change < 0.0m then failwith "cannot change negative amounts"
match coins |> List.tryFind (fun (_,c) -> change >= c) with
| Some (name,coin) ->
Console.WriteLine name
giveChange (change-coin)
| None -> failwith ("cannot find a coin smaller than " + string change)
这些都会显着改变你的算法,所以我不会向你展示更多的代码,但你应该考虑第二个:
而不是做&#34; 1.20 - &gt;给四分之一 - &gt;给四分之一 - &gt;给四分之一 - &gt;给四分之一 - &gt; ...&#34;很容易看出你在1.20中使用mod / div以聪明的方式有4个季度:D