declare const HasURI: unique symbol export interface Has { readonly URI: typeof HasURI readonly [K: symbol]: A } declare const TagURI: unique symbol export interface Tag { readonly [TagURI]: A readonly key: symbol } export const tag = (): Tag => ({ key: Symbol() } as Tag) export const singleton = (tag: Tag, a: A): Has => ({ [tag.key]: a } as Has) export const lookup = (tag: Tag) => (has: Has) => has[tag.key] export const upsertAt = (tag: Tag, b: B) => <_Has extends Has>(has: _Has): _Has & Has => ({ ...has, ...singleton(tag, b), }) export const modifyAt = (tag: Tag, f: (b: B) => B) => <_Has extends Has>(has: _Has) => upsertAt(tag, f(lookup(tag)(has)))(has)