Difference between revisions of "DDC/PolymorphicUpdate"

From HaskellWiki
< DDC
Jump to navigation Jump to search
 
(9 intermediate revisions by the same user not shown)
Line 1: Line 1:
  +
'''This is outdated information'''. The DDC project has moved to [http://discus-lang.org http://discus-lang.org]
  +
  +
  +
 
== Get/Set ==
 
== Get/Set ==
 
Consider the following function:
 
Consider the following function:
Line 11: Line 15:
 
</haskell>
 
</haskell>
   
This function allocates a box which can store a value and returns a tuple of functions which can be used to get and set that value.
+
This function allocates a box which can store a value, and returns a tuple of functions to get and set that value.
   
 
As the function is polymorphic, we can create boxes of whatever type we would like:
 
As the function is polymorphic, we can create boxes of whatever type we would like:
Line 17: Line 21:
 
<haskell>
 
<haskell>
 
main ()
 
main ()
= do getSet = makeGetSet 5
+
= do getSet :: (() -> Int, Int -> ())
  +
getSet = makeGetSet 5
   
 
out $ fst getSet () -- prints '5'
 
out $ fst getSet () -- prints '5'
Line 25: Line 30:
 
</haskell>
 
</haskell>
   
The trouble comes when we create a box containing value of polymorphic type. Without closure typing we could define:
+
The trouble comes when we create a box containing a value of polymorphic type. Without closure typing we could define:
   
 
<haskell>
 
<haskell>
Line 33: Line 38:
 
</haskell>
 
</haskell>
   
As the list is empty, we can treat it as being of any type <hask>(forall a. [a])</hask>, but suppose we update it at two different types...
+
When a list is empty, we can treat it as being of any type <hask>(forall a. [a])</hask>, but suppose we update the box containing it at two different types...
   
 
<haskell>
 
<haskell>
Line 43: Line 48:
   
 
The type of <hask>getSet2</hask> has <hask>forall a.</hask> at the front, so there is nothing to stop us from calling the set function at both <hask>[Int]</hask> and <hask>[String]</hask>, but what should the type be when use the get function in the last line?
 
The type of <hask>getSet2</hask> has <hask>forall a.</hask> at the front, so there is nothing to stop us from calling the set function at both <hask>[Int]</hask> and <hask>[String]</hask>, but what should the type be when use the get function in the last line?
  +
  +
== Dangerous type variables ==
  +
Ultimately, the problem illustrated above arose because there wasn't a mechanism to track the sharing of data between successive calls to <hask>getSet2</hask>. When <hask>makeGetSet</hask> was evaluated it created a shared mutable object (the <hask>box</hask>) and then returned functions that had this object free in their closure.
  +
  +
In Disciple, <hask>makeGetSet</hask> has the full type:
  +
<haskell>
  +
makeGetSet
  +
:: forall a %r0 %r1
  +
. a -> Tuple2 %r1 (() -(!e0 $c0)> a) (a -(!e1 $c1)> ())
  +
:- !e0 = !Read %r0
  +
, !e1 = !{!Read %r0; !Write %r0}
  +
, $c0 = ${box : %r0; box : %r0 $> a}
  +
, $c1 = ${box : %r0; box : %r0 $> a}
  +
, Base.Mutable %r0
  +
</haskell>
  +
  +
In this type, we see the new closure term <hask>(box : %r0 $> a)</hask>. This term says that the closure contains an object named <hask>box</hask> which is in a region <hask>%r0</hask>, and the type of the object includes a variable <hask>'a'</hask>. When <hask>%r0</hask> is <hask>Mutable</hask> we say that <hask>a</hask> is ''dangerous'', and dangerous variables are never generalised when they are free in the (outer most) closure of a function.

Latest revision as of 00:47, 24 February 2018

This is outdated information. The DDC project has moved to http://discus-lang.org


Get/Set

Consider the following function:

makeGetSet :: forall a. a -> (() -> a, a -> ())
makeGetSet x
 = do 	box	= Just x
	get ()	= case box of { Just z -> z; }
	set z	= box#x #= z
	(get, set)

This function allocates a box which can store a value, and returns a tuple of functions to get and set that value.

As the function is polymorphic, we can create boxes of whatever type we would like:

main ()
 = do	getSet :: (() -> Int, Int -> ())
        getSet	= makeGetSet 5

 	out $ fst getSet ()   -- prints '5'

	snd getSet 23         -- update the box
	out $ fst getSet ()   -- prints '23'

The trouble comes when we create a box containing a value of polymorphic type. Without closure typing we could define:

        ...
        getSet2 :: forall a. (() -> [a], [a] -> ())
        getSet2 = makeGetSet []

When a list is empty, we can treat it as being of any type (forall a. [a]), but suppose we update the box containing it at two different types...

       snd getSet2 [23]
       snd getSet2 ["trouble"]

       out $ fst getSet2 ()

The type of getSet2 has forall a. at the front, so there is nothing to stop us from calling the set function at both [Int] and [String], but what should the type be when use the get function in the last line?

Dangerous type variables

Ultimately, the problem illustrated above arose because there wasn't a mechanism to track the sharing of data between successive calls to getSet2. When makeGetSet was evaluated it created a shared mutable object (the box) and then returned functions that had this object free in their closure.

In Disciple, makeGetSet has the full type:

makeGetSet
        :: forall a %r0 %r1
        .  a -> Tuple2 %r1 (() -(!e0 $c0)> a) (a -(!e1 $c1)> ())
        :- !e0        = !Read %r0
        ,  !e1        = !{!Read %r0; !Write %r0}
        ,  $c0        = ${box : %r0; box : %r0 $> a}
        ,  $c1        = ${box : %r0; box : %r0 $> a}
        ,  Base.Mutable %r0

In this type, we see the new closure term (box : %r0 $> a). This term says that the closure contains an object named box which is in a region %r0, and the type of the object includes a variable 'a'. When %r0 is Mutable we say that a is dangerous, and dangerous variables are never generalised when they are free in the (outer most) closure of a function.