[Haskell-cafe] Caching the Result of a Transaction?

Matthew Brecknell haskell at brecknell.org
Sat Apr 26 23:37:25 EDT 2008

Conal Elliott said:
> Can we implement a type 'TIVal a' (preferably without unsafePerformIO)
> with the following interface:
>     newIVal :: STM (TIVal a, a -> STM ()) -- or IO (...)
>     force   :: TIVal a -> STM a
>     instance Functor     IVal
>     instance Applicative IVal
>     instance Monad       IVal
> where
> * 'newIVal' makes something like an IVar that can be written/defined
>   (just once) with the returned a->STM().
> * 'force' gets the value, retrying if not yet defined; once force is able
>   to succeed, it always yields the same value.
> * 'fmap f tiv' becomes defined (force yields a value instead of retrying)
>   when tiv does.  Similarly for (<*>) and join.
> * Forcing 'fmap f tiv' more than once results in f being called only
>   once,
> i.e., the result is cached and reused, as in pure values.  Similarly for
> (<*>) and join.

Perhaps what you and Jake are looking for are fully-fledged "triggers"
on transactional memory. To solve the fmap problem, have each TIVar
backed by a separate TVar. Then the TIVar returned by fmap would act as
a cache for the original TIVar. A trigger would watch the TVar which
backs the original TIVar, updating the cache TVar when the original
TIVar is written. Nested fmaps would work simply as a cascade of

The STM authors considered the possibility of triggers in their paper on
invariants [1], but instead took the safer option of read-only


More information about the Haskell-Cafe mailing list