You are actually not identifying which aspects of the code you are having trouble with.
-
The code starts with
CachedFib.fib/1
which simply invokesCache.run/1
- supplying it’s own anonymous function for calculating any desired value withCachedFib.cached_fib/2
. What could be a bit more clear here is thatcache
is a process identifier (PID). -
CachedFib.cached_fib/2
tries to look up the value but also supplies an alternate function to calculate the requested value (by accessing the two “previous” values from the “cache process”cache
and summing them). Supplying this “backup strategy” function feels weird but is a concession to the agent - agents only hold state - not logic. So any logic has to be supplied externally. The point here is thatCache
simply caches key value pairs - how these key value pairs are generated is up to the client. (Ultimately agents aren’t that useful but in Elixir learning resources they are often used as a first exposure to processes). -
Meanwhile
Cache.run/1
simply starts up the agent and stores the initial values forn = 0
andn = 1
in the agent (to be consistent this initial value should really come fromCacheFib.fib/1
asCacheFib.cache_fib/2
also supplies the logic for calculating key/value pairs). The second expression hands the passed anonymous functionbody
the agent’s PID (grantingCachedFib.cached_fib/2
access to the agent’s state so that it can be accessed and manipulated with the remainingCache
functions) binding the finalresult
of thebody
function. The third expression terminates the agent process. The fourth and final expression simply returns theresult
generated by the second expression. -
The remaining
Cache
functions concern themselves with looking up previously calculated values or adding new ones as generated by theif_not_found
function - i.e.:
fn -> cached_fib(n-2, cache) + cached_fib(n-1, cache) end
-
Cache.set/3
creates a new “state” for the agent by taking the map already stored in the agent and adding{n,val}
to it. Note the definition ofAgent.get_and_update/3
-Cache.set/3
will returnval
which is only part of the{n,val}
pair - i.e. the calculated value. -
Cache.complete_if_not_found/4
uses pattern matching across two function clauses (defining one function). The first clause (the first argument value isnil
) is invoked when a requested value wasn’t found in the map (stored as state in the agent); the suppliedif_not_found
function is invoked to generate the desired value and the result is pipelined intoCache.set/3
to update the agent’s state. Note that calculated result will be returned byCache.set/3
. The secondcomplete_if_not_found/4
function clause simply returns thevalue
it was given (from the map stored as the agent state). -
Cache.lookup/3
simply tries to look up the requested value. The result drives what happens withCache.complete_if_not_found/4
- it either simply returns the looked up value or generates the required value with the suppliedif_not_found
function.