これが正しいかどうか、またはより良い方法があるかどうか、またはこの問題を既に解決している既存のライブラリがあるかどうかはわかりません。
特に、CAS がメモリ フェンスを必要とするかどうかはわかりません。
エージェントと変更可能な辞書も試してみましたが、遅くなるという私の直感が確認され、実装がより複雑になりました。
module CAS =
open System.Threading
let create (value: 'T) =
let cell = ref value
let get () = !cell
let rec swap f =
let before = get()
let newValue = f before
match Interlocked.CompareExchange<'T>(cell, newValue, before) with
| result when obj.ReferenceEquals(before, result) ->
newValue
| _ ->
swap f
get, swap
module Memoization =
let timeToLive milis f =
let get, swap = CAS.create Map.empty
let evict key =
async {
do! Async.Sleep milis
swap (Map.remove key) |> ignore
} |> Async.Start
fun key ->
let data = get()
match data.TryFind key with
| Some v -> v
| None ->
let v = f key
swap (Map.add key v) |> ignore
evict key
v