我有一个coins = [200; 100; 50; 20; 10; 5; 2; 1]
列表和这个递归函数来计算有多少种方法可以给出一定数量的变化(欧拉项目问题 31的剧透警报):
let rec f acc coins amount =
if amount < 0 then 0L
elif amount = 0 then acc
else
match coins with
| [] -> 0L
| c::cs ->
f (acc + 1L) coins (amount - c) + f acc cs amount
除了StackOverflowException
大值之外,该函数需要很长时间。所以我想起了Y 组合器,并且很好奇如何将它应用到这个问题上。通过一点帮助和对函数签名的两个小改动,我得出了这个结论:
let f f acc coins amount =
if amount < 0 then 0L
elif amount = 0 then acc
else
match coins with
| [] -> 0L
| c::cs ->
f (acc + 1L) coins (amount - c) + f acc cs amount
let rec Y f x = f (Y f) x
这有效,现在我想使用字典进行缓存。但为此,我不知道如何处理acc
和的coins
论点f
。
在下面的代码中,字典已经有了一个疯狂的类型。在对函数进行柯里化后,它变成了一个int -> int64
,所以我希望我的字典有这两个类型参数,但事实并非如此。它编译并给出了正确的答案,但对于大输入来说它仍然很慢——对于那种类型来说不足为奇。
open System.Collections.Generic
let memoize (d:Dictionary<_, _>) f x =
match d.TryGetValue(x) with
| true, re -> re
| _ ->
let re = f x
d.Add(x, re)
re
let numberOfWaysToChange =
let d = Dictionary<_,_>()
fun x -> Y (f >> fun f x -> memoize d f x) 0L coins x
我尝试在所有地方粘贴两个初始化参数0L
和列表,但我无法让任何其他变体正常工作。
我怎样才能使这个例子中的缓存工作,我。e. 如何修复参数以使我的缓存属于类型Dictionary<int, int64>
?
PS:我知道 myf
不是尾递归的,所以我可以用acc
umulator 参数省去麻烦(也需要学习延续)。