I have a list coins = [200; 100; 50; 20; 10; 5; 2; 1]
and this recursive function to calculate how many ways to give a certain amount of changes (Spoiler alert for Project Euler problem 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
Besides a StackOverflowException
for large values, the function takes a very long time. So I remembered Y combinator and was curious how to apply it to this problem. With a little help and two small changes in the signature of the function I came to:
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
This works, and now I want to use the dictionary for caching. But I do not know what to do with the arguments acc
and coins
up f
.
. currying 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
, - .
, , i. . , Dictionary<int, int64>
?
PS: , f
, acc
umulator ( ).