Suppose that we have a reference <hask>r :: Ref (Maybe Int)</hask> and we would like to expose an editor of it to the user. The exposed editor would contain a checkbox and an integer entry field. If the checkbox is unchecked, the value of <hask>r</hask> should be <hask>Nothing</hask>, otherwise it should be <hask>Just i</hask> where <hask>i</hask> is the value of the entry field.

Suppose that we have a reference <hask>r :: Ref (Maybe Int)</hask> and we would like to expose an editor of it to the user. The exposed editor would contain a checkbox and an integer entry field. If the checkbox is unchecked, the value of <hask>r</hask> should be <hask>Nothing</hask>, otherwise it should be <hask>Just i</hask> where <hask>i</hask> is the value of the entry field.

−

The problem is that we cannot remember the value of the entry field if the checkbox is unchecked! Lens-chains give a nice solution to this problem.

+

The problem is that we cannot remember the value of the entry field if the checkbox is unchecked! Dependent reference creation give a nice solution to this problem.

==== Specification ====

==== Specification ====

−

Suppose that we have an abstract data type <hask>S</hask> with the following operations:

+

Suppose that we have an abstract data type <hask>S</hask> with the operations

<haskell>

<haskell>

Line 255:

Line 277:

<hask>extend'</hask> introduces a dependent local state because <hask>q</hask> is automatically updated if <hask>r</hask> changes (and vice-versa).

<hask>extend'</hask> introduces a dependent local state because <hask>q</hask> is automatically updated if <hask>r</hask> changes (and vice-versa).

−

Backward lens application can solve long-standing problems with application of lenses, but that is another story to tell.

+

Backward lens application can solve long-standing problems with application of lenses, see [[LGtk/ADT_lenses]].

==== Reference creation API (revised) ====

==== Reference creation API (revised) ====

Line 271:

Line 293:

<haskell>

<haskell>

extRef :: Monad m => Ref b -> Lens a b -> a -> C m (Ref a)

extRef :: Monad m => Ref b -> Lens a b -> a -> C m (Ref a)

−

extRef r k a0 = mapStateT (return . runIdentity) $ extend' r k a0

+

extRef r k = mapStateT (return . runIdentity) . extend' r k

</haskell>

</haskell>

Line 283:

Line 305:

* Derived <hask>MonadTrans</hask> instance of <hask>C</hask> to be able to lift operations in the <hask>m</hask> monad.

* Derived <hask>MonadTrans</hask> instance of <hask>C</hask> to be able to lift operations in the <hask>m</hask> monad.

−

Note that <hask>newRef</hask> can be defined in terms of <hask>extRef</hask> so <hask>extRef</hask> is more expressive than <hask>newRef</hask>:

+

Note that <hask>newRef</hask> can be defined in terms of <hask>extRef</hask> so <hask>extRef</hask> is more powerful than <hask>newRef</hask>:

<haskell>

<haskell>

Line 290:

Line 312:

</haskell>

</haskell>

−

==== Implementation ====

+

==== Existence proof of <hask>S</hask> ====

We prove constructively, by giving a reference implementation, that <hask>S</hask> exists. With this we also prove that <hask>S</hask> defined in the previous section exists because <hask>extend</hask> can be defined in terms of <hask>extend'</hask> (easy exercise: give the definition).

We prove constructively, by giving a reference implementation, that <hask>S</hask> exists. With this we also prove that <hask>S</hask> defined in the previous section exists because <hask>extend</hask> can be defined in terms of <hask>extend'</hask> (easy exercise: give the definition).

Line 312:

Line 334:

<haskell>

<haskell>

−

data Part = forall a . Part (S -> a -> a) a

+

data Part

+

= forall a

+

. Part

+

{ selfAdjustment :: S -> a -> a -- does not change (static)

+

, statePart :: a -- variable

+

}

</haskell>

</haskell>

−

Note that instead of lenses, just set functions are stored, a simplification in the implementation.

+

Note that instead of lenses, self-adjusting functions are stored in state parts, which is a simplification in the implementation.

When a new reference is created, both the state and the lens-chain are extended. The dependency between the newly created state part and the old state parts can be encoded into the new lens in the lens-chain.

When a previously created reference (i.e. a lens) is accessed with a state after several extensions, a proper prefix of the lens-chain makes possible to convert the program state such that it fits the previously created reference.

Reference implementation:

Definition of

S

:

type S =[Part]

data Part
=forall a
. Part
{ selfAdjustment :: S -> a -> a -- does not change (static), statePart :: a -- variable}

Note that instead of lenses, self-adjusting functions are stored in state parts, which is a simplification in the implementation.