Version 4 (modified by benl, 4 years ago)


< Overview

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 Show 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.