diff options
Diffstat (limited to 'codingquest2024/src/utilities')
-rw-r--r-- | codingquest2024/src/utilities/memo.gleam | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/codingquest2024/src/utilities/memo.gleam b/codingquest2024/src/utilities/memo.gleam new file mode 100644 index 0000000..b06d8fd --- /dev/null +++ b/codingquest2024/src/utilities/memo.gleam @@ -0,0 +1,57 @@ +import gleam/dict.{type Dict} +import gleam/otp/actor.{type Next, Continue, Stop} +import gleam/erlang/process.{type Subject, Normal} +import gleam/option.{None} + +const timeout = 1000 + +type Message(k, v) { + Shutdown + Get(key: k, client: Subject(Result(v, Nil))) + Set(key: k, value: v) +} + +type Server(k, v) = + Subject(Message(k, v)) + +pub opaque type Cache(k, v) { + Cache(server: Server(k, v)) +} + +fn handle_message( + message: Message(k, v), + dict: Dict(k, v), +) -> Next(Message(k, v), Dict(k, v)) { + case message { + Shutdown -> Stop(Normal) + Get(key, client) -> { + process.send(client, dict.get(dict, key)) + Continue(dict, None) + } + Set(key, value) -> Continue(dict.insert(dict, key, value), None) + } +} + +pub fn create(apply fun: fn(Cache(k, v)) -> t) -> t { + let assert Ok(server) = actor.start(dict.new(), handle_message) + let result = fun(Cache(server)) + process.send(server, Shutdown) + result +} + +pub fn set(in cache: Cache(k, v), for key: k, insert value: v) -> Nil { + process.send(cache.server, Set(key, value)) +} + +pub fn get(from cache: Cache(k, v), fetch key: k) -> Result(v, Nil) { + process.call(cache.server, fn(c) { Get(key, c) }, timeout) +} + +pub fn memoize(with cache: Cache(k, v), this key: k, apply fun: fn() -> v) -> v { + let result = case get(from: cache, fetch: key) { + Ok(value) -> value + Error(Nil) -> fun() + } + set(in: cache, for: key, insert: result) + result +} |