Sök…


Enkel memoization

Memoization består av cachefunktionsresultat för att undvika att beräkna samma resultat flera gånger. Detta är användbart när du arbetar med funktioner som gör kostsamma beräkningar.

Vi kan använda en enkel fabriksfunktion som exempel:

let factorial index =
    let rec innerLoop i acc =
        match i with
        | 0 | 1 -> acc
        | _ -> innerLoop (i - 1) (acc * i)

    innerLoop index 1

Att ringa denna funktion flera gånger med samma parameter resulterar i samma beräkning om och om igen.

Memoization hjälper oss att cache factorialresultatet och returnera det om samma parameter skickas igen.

Här är en enkel implementering av memoization:

// memoization takes a function as a parameter
// This function will be called every time a value is not in the cache
let memoization f =
    // The dictionary is used to store values for every parameter that has been seen
    let cache = Dictionary<_,_>()
    fun c ->
        let exist, value = cache.TryGetValue (c)
        match exist with
        | true -> 
            // Return the cached result directly, no method call
            printfn "%O -> In cache" c
            value
        | _ -> 
            // Function call is required first followed by caching the result for next call with the same parameters
            printfn "%O -> Not in cache, calling function..." c
            let value = f c
            cache.Add (c, value)
            value

memoization tar helt enkelt en funktion som en parameter och returnerar en funktion med samma signatur. Du kan se detta i metodsignaturen f:('a -> 'b) -> ('a -> 'b) . På det här sättet kan du använda memisering på samma sätt som om du kallade den faktormetoden.

printfn samtalen ska visa vad som händer när vi anropar funktionen flera gånger; de kan tas bort på ett säkert sätt.

Att använda memoization är enkelt:

// Pass the function we want to cache as a parameter via partial application
let factorialMem = memoization factorial

// Then call the memoized function
printfn "%i" (factorialMem 10)
printfn "%i" (factorialMem 10)
printfn "%i" (factorialMem 10)
printfn "%i" (factorialMem 4)
printfn "%i" (factorialMem 4)

// Prints
// 10 -> Not in cache, calling function...
// 3628800
// 10 -> In cache
// 3628800
// 10 -> In cache
// 3628800
// 4 -> Not in cache, calling function...
// 24
// 4 -> In cache
// 24

Memoering i en rekursiv funktion

Använd det föregående exemplet för att beräkna faktoriet för ett heltal, lägg i hashtabellen alla värden på faktoria som beräknas inuti rekursionen, som inte visas i tabellen.

Liksom i artikeln om memoisation , deklarerar vi en funktion f som accepterar en funktionsparameter fact och en heltal parameter. Denna funktion f , innehåller instruktioner för att beräkna faktorn för n från fact(n-1) .

Detta gör det möjligt att hantera rekursion genom den funktion som returneras av memorec och inte av fact och eventuellt stoppa beräkningen om fact(n-1) redan har beräknats och finns i hashtabellen.

let memorec f =
   let cache = Dictionary<_,_>()
   let rec frec n = 
       let value = ref 0
       let exist = cache.TryGetValue(n, value)
       match exist with
       | true -> 
           printfn "%O -> In cache" n
       | false ->
           printfn "%O -> Not in cache, calling function..." n
           value := f frec n
           cache.Add(n, !value)
       !value
   in frec

let f = fun fact n -> if n<2 then 1 else n*fact(n-1)

[<EntryPoint>]
let main argv = 
    let g = memorec(f)
    printfn "%A" (g 10)
    printfn "%A" "---------------------"
    printfn "%A" (g 5)
    Console.ReadLine()
    0

Resultat:

10 -> Not in cache, calling function...
9 -> Not in cache, calling function...
8 -> Not in cache, calling function...
7 -> Not in cache, calling function...
6 -> Not in cache, calling function...
5 -> Not in cache, calling function...
4 -> Not in cache, calling function...
3 -> Not in cache, calling function...
2 -> Not in cache, calling function...
1 -> Not in cache, calling function...
3628800
"---------------------"
5 -> In cache
120


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow