How to get caching with Y-combinator for this function

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 StackOverflowExceptionfor 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 accand coinsup 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 ( ).

+4
1

, Y combinator memoization.

let rec Y f x = f (Y f) x
// val Y : f:(('a -> 'b) -> 'a -> 'b) -> x:'a -> 'b

let memoize f =
    let d = new System.Collections.Generic.Dictionary<_,_>()
    let rec g x =
        match d.TryGetValue x with
        | true, res -> res
        | _ -> let res = f g x in d.Add(x, res); res
    g
// val memoize : f:(('a -> 'b) -> 'a -> 'b) -> ('a -> 'b) when 'a : equality

.

let cc f = function
| amount, _ when amount = 0 -> 1
| amount, _ when amount < 0 -> 0
| _, [] -> 0
| amount, hd::tl -> f (amount, tl) + f (amount - hd, hd::tl)

#time;;
Y cc (200, [200; 100; 50; 20; 10; 5; 2; 1])
memoize cc (200, [200; 100; 50; 20; 10; 5; 2; 1])
+1

Source: https://habr.com/ru/post/1692203/


All Articles