⍝ Function memoization:
      ⎕io←1
      afib←{⎕io←0                   ⍝ Naïve coding of ⍺-fibonacci number.
          ⍵∊⍳⍺:⍵                    ⍝ small number: done,
          +/⍺ afib¨⍵-1+⍳⍺           ⍝ otherwise: sum of preceding ⍺ fib numbers.
      }
      2 afib¨⍳10                    ⍝ *slow* ⍺-fibonacci sequence.
1 1 2 3 5 8 13 21 34 55
      afib←(afib)memo(cache ⍬)      ⍝ Memoize afib.
      2 afib¨⍳20                    ⍝ *fast* ⍺-fibonacci sequence.
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
⍝ Notice that afib is coded to use its own name explicitly, rather than '∇'
⍝ for the recursion. This is so that the recursive call references the newly-
⍝ assigned derived function, whereas '∇' would have referenced the original
⍝ function and circumvented the memoization.
⍝ Perhaps surprisingly, the cache can be relied upon to supply the "base values"
⍝ of the recursion, thus simplifying the initial function coding.
      fib←{                         ⍝ Naïve coding of regular fibonacci number.
          +/fib¨⍵-1 2               ⍝ sum of preceding 2 fib numbers.
      }
      fib←(fib)memo(cache 2/¨0 1)   ⍝ Cache pre-populated with base values.
      fib¨⍳20                       ⍝ Fast fibonacci sequence.
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
      div←÷ memo (cache ⍬)          ⍝ Ambivalent operand function
      2 div 7                       ⍝ Dyadic use distinct from ...
0.2857142857
      div 2 7                       ⍝ ... monadic use.
0.5 0.1428571429
      osc←{                         ⍝ Oscillate - probably returns 1.
          2|⍵:osc 1+3×⍵             ⍝ odd:  triple 'n add-one,
              osc ⍵÷2               ⍝ even: halve.
      }
      ∆osc←cache⊂1 1                ⍝ Initialise cache for osc.
      osc←(osc)memo ∆osc            ⍝ derive "fast" osc function.
      ∆osc.⎕nl 2                    ⍝ cache-space contents.
keys
vals
      show←{                            ⍝ Show cache <rslts ← args>
          ⍕↑⍵.(vals{⍺'←',⊂¯1↓⍵}¨keys)   ⍝ (dropping extra rarg).
      }
      show ∆osc                     ⍝ Show initial cache.
1 ← 1 
      osc 2                         ⍝ Apply derived function, extending cache.
1
      show ∆osc                     ⍝ Show extended cache.
1 ← 1 
1 ← 2 
      osc 3                         ⍝ Apply function again.
1
      show ∆osc                     ⍝ Show extended cache.
1 ← 1  
1 ← 2  
1 ← 4  
1 ← 8  
1 ← 16 
1 ← 5  
1 ← 10 
1 ← 3  
      zap←{⎕ml←0                        ⍝ Remove value ⍵ from cache ⍺.
          ⍺.{⎕ml←0                      ⍝ within cache:
              mask←⍵∘≡¨↓⍉↑vals keys     ⍝ mask of matches.
              {1}vals keys/⍨←⊂~mask     ⍝ retain non-matches.
          }(⊃⍵)(1↓⍵,¯1↑⍵)               ⍝ target value and key.
      }
      ∆osc∘zap¨(1 16)(1 10)(1 3)    ⍝ Zap selected cache entries.
1 1 1
      show ∆osc                     ⍝ Show compacted cache.
1 ← 1 
1 ← 2 
1 ← 4 
1 ← 8 
1 ← 5 
      osc 3                         ⍝ Re-run function.
1
      show ∆osc                     ⍝ Partially restored cache.
1 ← 1  
1 ← 2  
1 ← 4  
1 ← 8  
1 ← 5  
1 ← 10 
1 ← 3  
      +⎕ex'∆osc'                    ⍝ Seal access to osc's cache.
1
      osc¨⍳10                       ⍝ Derived function still operates normally.
1 1 1 1 1 1 1 1 1 1
⍝∇ memo cache
Back to: code
Back to: Workspaces