# Lookups

The examples run inside an [active graph](graph.fsx).

`createLookup f affected source` computes `f state key` for each key you read with `Get`.
Unlike a [projection](projections.fsx), a lookup has no fixed key set: it creates cells for
requested keys. For the common case of selection membership, use a [selector](selectors.fsx).
When the source changes, it recomputes live cells for the keys returned by `affected prev next`.

:::details Cell lifetime
An unobserved cell is evicted on the next source transition or read of another key.
:::

```fsharp
let stock = createSignal (Map [ "apples", 3; "pears", 0 ])

let changedKeys (prev: Map<string, int>) (next: Map<string, int>) =
    Seq.append prev.Keys next.Keys
    |> Seq.distinct
    |> Seq.filter (fun k -> prev.TryFind k <> next.TryFind k)

let onHand =
    createLookup (fun (m: Map<string, int>) k -> m.TryFind k |> Option.defaultValue 0) changedKeys (fun () -> stock.Value)

onHand.Get "apples", onHand.Get "plums"
```

```text
(3, 0)
```

:::warning The `affected` function is a contract

`affected prev next` must name every key whose value can differ between
the two states. A key left out keeps its stale value. An extra key costs one recomputation.
:::

Change the apple count while the pear reader stays quiet. The lookup's `affected` function
names only the key whose count changed.

<div class="partas-solid-card partas-solid-card--map">

<div class="partas-solid" data-partas-page="p4f083adedb" data-partas-cell="c1"></div>

</div>

:::details Failed and pending lookup cells

A key whose computation throws holds the exception, and is recomputed on every later transition until
it succeeds. A pending source suspends every live cell until it settles.

:::
