Skip to main content Link Search Menu Expand Document (external link)

Cache overview

Mutable cache with optional bounded capacity and optional time-to-live built around a user-supplied lookup function. The lookup function may be recursive, in which case the cache is also used to detect circularity.

Mental model

  • Type<A, B> is a mutable store mapping keys of type A to values of type B, populated on demand by lookUp.
  • Keys are compared with Equal.equals (the underlying store is a MutableHashMap).
  • Eviction is FIFO: when capacity is exceeded the oldest insertion is evicted first.
  • When lifeSpan elapses for an entry, the next read triggers a fresh lookup; entries inserted before the expired one are also evicted in the process to keep insertion order consistent with age.

Common tasks

  • Construct: {@link make}
  • Read: {@link get}, {@link toGetter}
  • Inspect: {@link toKeys}

Gotchas

  • The cache is mutableget mutates the underlying store. Sharing a cache across fibers without external coordination is unsafe.
  • When the lookup function is recursive, capacity may be temporarily exceeded: every key in the recursion chain is reserved (with an empty entry) before a result is produced, so a chain of n recursive calls reserves n entries even past capacity. Excess entries are reclaimed once the recursion unwinds.
  • When isCircular is true, the value returned by lookUp is never stored, regardless of the second tuple element.

Quickstart

Example (Basic cache usage)

import { Tuple, pipe } from "effect"
import * as MCache from "@parischap/effect-lib/MCache"

const cache = MCache.make({
  lookUp: ({ key }: { readonly key: number }) => Tuple.make(key * 2, true)
})

console.log(pipe(cache, MCache.get(5))) // 10

Table of contents


Constructors

make

Builds a new cache backed by lookUp.

  • Use to wrap an expensive function in a cache. Keys are compared with Equal.equals.
  • capacity defaults to Infinity (unbounded).
  • lifeSpan defaults to Infinity (entries never expire).

Example (Bounded cache with TTL)

import { Tuple } from "effect"
import * as MCache from "@parischap/effect-lib/MCache"

const cache = MCache.make({
  lookUp: ({ key }: { readonly key: number }) => Tuple.make(key * 2, true),
  capacity: 100,
  lifeSpan: 60_000 // 1 minute
})

Signature

export declare const make: <A, B>({
  lookUp,
  capacity,
  lifeSpan
}: {
  readonly lookUp: LookUp<A, B>
  readonly capacity?: number
  readonly lifeSpan?: number
}) => Type<A, B>

Models

LookUp (interface)

Type of the lookup function passed to {@link make}. The lookup receives a record carrying the key to look up, an isCircular flag, and a memoized callback that re-enters the cache recursively when isCircular is false.

  • The function returns a [result, storeInCache] tuple. storeInCache only acts as a hint: when isCircular is true, the value is never stored regardless of storeInCache.
  • Use the memoized parameter inside the lookup body to recurse through the cache instead of calling the lookup directly; this enables circularity detection.

Signature

export interface LookUp<A, B> extends MTypes.OneArgFunction<
  | { readonly key: A; readonly memoized: undefined; readonly isCircular: true }
  | { readonly key: A; readonly memoized: (a: A) => B; readonly isCircular: false },
  MTypes.Pair<B, boolean>
> {}

Type (class)

Type of a cache.

Signature

export declare class Type<A, B> {
  private constructor(params: MTypes.Data<Type<A, B>>)
}

make (static method)

Static constructor.

Signature

static make<A, B>(params: MTypes.Data<Type<A, B>>): Type<A, B>

[MData.idSymbol] (method)

Returns the id of this.

Signature

[MData.idSymbol](): string | (() => string)

store (property)

The underlying store. A key mapped to Option.none means a lookup is currently in progress (used to detect circular recursion).

Signature

readonly store: MutableHashMap.MutableHashMap<A, Option.Option<MCacheValueContainer.Type<B>>>

keyListInOrder (property)

The order in which keys were inserted, used to evict the oldest first when the cache reaches its capacity.

Signature

readonly keyListInOrder: MutableList.MutableList<A>

lookUp (property)

The lookup function used to populate the cache.

Signature

readonly lookUp: LookUp<A, B>

capacity (property)

The capacity of the cache. Infinity means unbounded; NaN or a negative value is normalized to 0.

Signature

readonly capacity: number

lifeSpan (property)

The lifespan of cached values, in milliseconds. Infinity means values never expire; NaN or a negative value is normalized to 0. A 0 lifespan means every subsequent lookup considers the entry expired.

Signature

readonly lifeSpan: number

Module markers

moduleTag

Module tag.

Signature

export declare const moduleTag: "@parischap/effect-lib/Cache/"

Utils

get

Reads the value associated with a from self. Triggers a lookup when the key is missing or its entry has expired.

  • Keys are compared with Equal.equals.
  • When the lookup is already in progress for a (recursive call), lookUp is invoked with isCircular: true and the returned value is not stored.
  • On expiration of an entry, every entry inserted before it is evicted as well to keep the FIFO insertion order in sync with element age.

Example (Reading from the cache)

import { Tuple, pipe } from "effect"
import * as MCache from "@parischap/effect-lib/MCache"

const cache = MCache.make({
  lookUp: ({ key }: { readonly key: number }) => Tuple.make(key * 2, true)
})

console.log(pipe(cache, MCache.get(5))) // 10

Signature

export declare const get: <A>(a: A) => <B>(self: Type<A, B>) => B

toGetter

Returns a getter bound to self, suitable for point-free lookups.

  • Use when the same cache will be queried by many call sites and you want to capture it once.
  • Equivalent to (a) => MCache.get(a)(self).

Example (Reusable getter)

import { Tuple } from "effect"
import * as MCache from "@parischap/effect-lib/MCache"

const cache = MCache.make({
  lookUp: ({ key }: { readonly key: number }) => Tuple.make(key * 2, true)
})
const lookup = MCache.toGetter(cache)

console.log(lookup(5)) // 10

Signature

export declare const toGetter: <A, B>(self: Type<A, B>) => MTypes.OneArgFunction<A, B>

toKeys

Returns the keys whose value is currently present in the cache.

  • Keys whose lookup is in progress (i.e. mapped to Option.none) are excluded.
  • The order of the returned array reflects the iteration order of the underlying MutableHashMap, which is implementation-defined.

Example (Listing cached keys)

import { Tuple, pipe } from "effect"
import * as MCache from "@parischap/effect-lib/MCache"

const cache = MCache.make({
  lookUp: ({ key }: { readonly key: number }) => Tuple.make(key * 2, true)
})

pipe(cache, MCache.get(1))
pipe(cache, MCache.get(2))
console.log(MCache.toKeys(cache)) // [1, 2]

Signature

export declare const toKeys: <A, B>(self: Type<A, B>) => Array<A>