Cas*_*roy 0 f# functional-programming
我的方法是使用命令式代码尝试问题,然后使用惯用功能代码再次尝试相同的问题.
这是我目前正在解决的问题:
更改退货计划 - 用户输入成本,然后输入金额.该计划将弄清楚变化所需的季度,硬币,镍币,硬币的数量.
这是我天真(迫切)的解决方案:
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
Run Code Online (Sandbox Code Playgroud)
如何使用功能构造(即没有mutable)编写此代码?
在这种情况下,最简单的方法是将可变变量移动到函数参数中并使用递归(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)
Run Code Online (Sandbox Code Playgroud)
这是明显的翻译
当然,双ifs有点过时了:
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)
Run Code Online (Sandbox Code Playgroud)
当然,许多人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 -> ()
Run Code Online (Sandbox Code Playgroud)
我认为现在这是一个合理的解决方案.
这种情况永远不会发生,因为我们已经在那里获得了一些硬币(或者我们希望如此,因为如果有人付不够,而且价值变为负值,我们就会遇到麻烦) - 也许我们应该给出一些更好的暗示:
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)
Run Code Online (Sandbox Code Playgroud)
这些都会显着改变你的算法,所以我不会向你展示更多的代码,但你应该考虑第二个:
而不是做"1.20 - >给季度 - >给季度 - >给季度 - >给季度 - > ......"很容易看出你在1.20中使用mod/div以聪明的方式有4个季度:D