[reply copied to hugs-bugs and glasgow-haskell-bugs]

Bruce McKenzie <[EMAIL PROTECTED]> reports:
> The following small program
> 
> > import Array
> > main = print a
> >     where
> >       a :: Array Int Int
> >       a = array (1,0) []
> 
> gives an [Index out of range] error when executed [on Hugs]
> However ghc-2.01 gives no error producing as output
>     array (1, 0) []
> 
> Just like a list with no elements, an array with no indices is very useful.
> 
> I have studied the HTML versions of the draft Haskell 1.4 Library and I
> think (but it is not crystal clear) that it is legal to have an array
> with no elements. The question hinges on whether the (strict) testing
> of the validity of the indices by the fuction array will cause an error.
> As this translates to the test
>    and [inRange b i | (i,_) <- ivs]
> where ivs is the array of values (in my case []) and `and []' is True
> there should be no problem as far as I can see.
> 
> So, is this a bug or a misuse of the language?

The error reported by Hugs is caused by calling "Ix.rangeSize (1,0)"
to determine how big the array is.  Ix.rangeSize (1,0) calls "Ix.index
(1,0) 0" which produces an error as required by the report.

The report _doesn't_ say that you have to use rangeSize to calculate
the size of the array (in fact, the "definition" doesn't use it) but I
have absolutely no idea how I could calculate the size of an array
without calling rangeSize.  I'd guess that GHC uses rangeSize too but
that they omitted the error check on their highly optimised Int instance.

So, I think that Hugs is right and GHC is wrong.
[GHC folks - consider this to be a bug report :-)]


However, I think empty arrays are useful so I think the report should
be changed to make GHC right and Hugs wrong.  A minimal change would
be to make rangeSize a method of class Ix with this default declaration:

  rangeSize bs = length (range bs)

and add these equations to the list of laws that Ix instances should satisfy:

  rangeSize bs = length (range bs)
  index b i    = bottom  if not inRange b i

However, I think we should also fix the following flaws in the sample
implementation given in the report:

1) The sample implementation is completely unlike any implementation I've
   ever seen (and no clearer as a result).  This makes it hard to see:

   1) What role "index" has in array lookup - it isn't used anywhere in
      the sample implementation
   2) Does the implementation have the strictness properties we'd expect.
      (I think the answer is "yes" because it was very carefully designed
      - but I think a more direct implementation would make it clearer.)

2) The report used to say that this was a very inefficient implementation
   intended to define the semantics but not the operational behaviour.
   This statement seems to have been dropped.  Let's add it back in.
   
I think the simplest way to fix the report is to use a more obvious
representation for Arrays:

  data (Ix a) => Array a b = MkArray (a,a) [b] deriving ()

and to change the implementation of array and ! as follows:
(this code hasn't been tested)

     (MkArray bs vs) ! i = vs !! index bs i

     array bs@(l,h) ivs 
       | all (inRange bs . fst) ivs
       = error "Array.array: out-of-range array association"
       | otherwise
       = MkArray bs (map f (range bs))
      where
       f j = case filter (\(i,v) -> i == j) ivs of
             []  -> error "Array.!: undefined array element"
             [v] -> v
             _   -> error "Array.!: multiply defined array element"

--
Alastair Reid              Yale Haskell Project Hacker
[EMAIL PROTECTED]  http://WWW.CS.Yale.EDU/homes/reid-alastair/

Reply via email to