[Haskell-cafe] Mutable arrays

Don Stewart dons at galois.com
Wed Feb 6 11:33:59 EST 2008


jeff1.61803:
>    On Feb 6, 2008 1:18 AM, Jonathan Cast <[1]jonathanccast at fastmail.fm>
>    wrote:
> 
>      On 5 Feb 2008, at 10:14 PM, Jeff I* wrote:
> 
>        On Feb 5, 2008 4:58 PM, ChaddaA- FouchA(c)
>        <[2]chaddai.fouche at gmail.com> wrote:
> 
>          2008/2/5, Jeff I* <[3]jeff1.61803 at gmail.com>:
>          > This is interesting.  I've been programming in Concurrent Clean
>          for a while.
>          >  Instead of monads, Clean supports unique types for mutable arrays
>          and IO.
>          > In Clean, I can write code that iterates through a mutable array
>          by
>          > converting it to a lazy list.  This is convenient because I can
>          use all the
>          > nice list processing functions that are available.
>          >
> 
>          You could absolutely write something like that in Haskell, but as
>          some
>          have pointed out, this is probably _not a Good Idea_, even though it
>          works in your particular case, the array could be modified between
>          the
>          time you get the lazy list and the time you actually read it... And
>          there's no way to insure it's not happening in Haskell, and I
>          strongly
>          doubt there is in Concurrent Clean, could you confirm ?
> 
>        Concurrent Clean can handle this in a safe way.  Here's a code snippet
>        for normalize_2D_ary from ArrayTest.icl:
>        
>        uToList_2D :: *(a u:(b c)) -> (.[c],*(a u:(b c))) | Array a (b c) &
>        Array b c
>        map_in_place_2d_arr :: (a -> a) *(b *(c a)) -> *(b *(c a)) | Array b
>        (c a) & Array c a
>        normalize_2D_ary :: *(a *(b c)) -> *(a *(b c)) | Array a (b c) & Array
>        b c & / c & Ord c
>        normalize_2D_ary ary =
>            let (lst,ary2) = uToList_2D ary
>                max_elem = foldl1 max lst
>            in  map_in_place_2d_arr (\ x -> x / max_elem) ary2
>        uToList_2D takes a unique array, ary, and returns a tuple containing a
>        list of the array elements and a "new" array, ary2.  uToList_2D does
>        not modify ary, but Clean's type system forces any function that
>        accesses a unique array to thread the array through and return a "new"
>        array.  Under the hood the "new" array actually uses the same memory
>        storage as the original array.  So, it is effecient.  Threading the
>        array serializes access insuring the array won't be modified until
>        the list is complete.
> 
>      I'm confused --- does uToList_2D return the head of the list before or
>      after it finishes reading the array?  If before, then I don't see how
>      the type system prevents me from modifying the array before I finish
>      examining the list, as you claim.  If after, then the list isn't truly
>      lazy.
> 
>    
>    uToList_2D can return the head of the list before it finishes reading the
>    array.  I could modify the code so that it is ambiguous whether the array
>    is modified before the list processing is finished.
>    
>    normalize_2D_ary ary =
>        let (lst,ary2) = uToList_2D ary
>            max_elem = foldl1 max lst
>         in  map_in_place_2d_arr (\ x -> x / max_elem) ary  // I changed ary2
>    to ary
>    
>    However, the type system will generate an error with this code because
>    ary is no longer unique because it is referenced in two expressions. 
>    Clean produces this error message:
>    
>    Uniqueness error [ArrayTest.icl,55,normalize_2D_ary]: "ary" demanded
>    attribute cannot be offered by shared object
>    
>    I should mention that a problem with the code I've shown is that it is
>    very sensitive to the order in which the expression graph is evaluated. 
>    Simple changes can cause lst to become strict and the program to run out
>    of heap.
>    By the way, Clean has it's share of rough edges.  The reason I'm hanging
>    out on Haskell-Cafe is because I'm trying to get away from those rough
>    edges.  But, I am missing Clean's uniqueness types.  I'm starting to
>    see Haskell's unsafe functions as a blunt work around that could be fixed
>    elegantly and safely by implementing uniqueness types.

That's a reasonable critique : its hard to enforce uniqueness, in the
type system in Haskell, -- I'd be interesting to see approaches that
avoid extending the compiler.

-- Don


More information about the Haskell-Cafe mailing list