may be thought of as functions whose domains are isomorphic to contiguous subsets of the integers.
Arrays in Java:
An array object contains a number of variables. The number of variables may be zero, in which case the array is said to be empty. The variables contained in an array have no names; instead they are referenced by array access expressions that use nonnegative integer index values. These variables are called the components of the array. If an array has n components, we say n is the length of the array; the components of the array are referenced using integer indices from 0 to n - 1, inclusive.
This probably sums up the difference between the languages very well. Haskell says it in one sentence, whereas Java waffles a little bit more!
In Haskell arrays are constructed with the
array
constructor. The first argument specifies a pair of bounds so we can create an array mapping the integers 3, 4 and 5 to 10 times their value.
*Main> array (3,5) [ (i,i*10) | i <- [3..5]]
array (3,5) [(3,30),(4,40),(5,50)]
Arrays can also be multidimensional in which case more bounds need to be provided.
*Main> (array ((0,0),(1,1)) [ ((i,j),i*2+j) | i <- [0..1], j <- [0..1]])
array ((0,0),(1,1)) [((0,0),0),((0,1),1),((1,0),2),((1,1),3)]
I struggled to get the PPM package in Hackage working last time because I didn't understand arrays in the slightest. Now that I have a little understanding (only a little!) I can actually visualize the ray tracing code...
One thing I'm still not understanding is how I should format Haskell code. Here's the code to render the image and save it as a PPM.
image :: [Sphere] -> Point -> Int -> Int -> Array (Int,Int) Int
image world eye width height =
array
((0,0),(width,height))
[((i,j),truncate (255 * (value (colorAt world eye (fromIntegral i) (fromIntegral j))))) |
i <- [0..width], j<- [0..height]]
imageWord16 :: Array (Int,Int) Int -> Array (Int,Int) Word16
imageWord16 image = fmap (fromIntegral :: Int -> Word16) image
saveImage :: String -> [Sphere] -> Point -> Int -> Int -> IO ()
saveImage filename world eye width height = arrayToFile filename (imageWord16 (image world eye width height))
Note the horrible usage of
fromIntegral
and truncate
to convert an integer to a float and back again. I think this is because I should have been more general in my types on the Point data type and specified it as a number rather than a float.The type of
saveImage
looks a little funny but this is because it returns an IO action rather than a value. This value is a monad, but again I'll ignore this and hope repeatedly using them will lead to understanding! For now, I just grok that its type indicates it does something rather than returns something.![Hurrah, I can save images](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiZGGUuy3gk8U2gSpOscL72ftQPhL6I34r7CVmRcX12CkxFllDoVFKJi4PJimld8uVToOcwTdUOeYVPWa3DUJy1E01VtunntHyaW-dCQgFphLwYpDr7tLY45wJZnJOIs2hcOXn4xypvL0/s400/doeswork.png)
The finished code weighs in at about 100 lines, which is more or less exactly the same as Clojure, but with the advantage of static typing. I found static typing to be in equal measure incredibly useful and incredibly frustrating! Hopefully it'll lean towards useful as I understand things a bit more.