Version 1 (modified by benl, 4 years ago)

--

Destructive Update

Update of base values

Values can be updated with the (:=) operator, which copies its second argument over its first.

 main ()
  = do   x = 2
         putStrLn $ show x   -- prints '2'
 
         x := 3
         putStrLn $ show x   -- prints '3'

Update of algebraic data

The structure of algebraic data can be modified with the (#=) operator. This replaces the constructor at a particular node with a new one.

We'll use a simple point type as an example. In this definition, x and y are field names and are local to the Point type. This is different from Haskell, where all field names become functions in the top level scope.

 data Point
     = Point { x :: Float; y :: Float; }

We'll also define an instance of the <hask>Show</hask> type-class, so we can print out the result.

 instance Show Point where
     show (Point x y)	= parens (show x % "," % show y)	
}}}

Values of `Point` type are constructed in the standard way, and we can use the field names to access their components.

{{{
 main ()
  = do   point  = Point 2.0 3.0  -- construct a new point
         putStrLn $ show point               -- prints '(2.0, 3.0)' 
	 putStrLn $ show point.x             -- prints '2.0'
}}}

Projecting the `x` field gives us the `Float` object inside `point`. 
{{{
         oldX   = point.x
         putStrLn $ show oldX                -- prints '2.0'
}}}

Binding a literal value allocates a new object.
{{{
         newX = 5.0
}}}

We can now make `point` reference this new object.
{{{
         point#x #= newX
         putStrLn $ show point               -- prints '(5.0, 3.0)'
         putStrLn $ show oldX                -- oldX is still '2.0'
}}}

== Reference projections ==
In Disciple, we don't need to change our data definitions to include `Ref` or `IORef` types before we can update them. References are created on the fly with the reference projection operator `(#)`.

In the previous example, when we used `(#)` a reference was created which held a pointer ''into'' the `point` object.
{{{
        (point # x) :: Ref Float
}}}

The `(#=)` operator is just a regular function which has type:
{{{
        (#=) :: forall a. Ref a -> a -> ()
}}}

When we then evaluated:
{{{
        point#x #= newX
}}}
The pointer inside `point` which used to reference `oldX` was updated to reference to `newX`.