> Hi, I'd like to call LaPack routines from Haskell. > Having read the GreenCard documentation it's still not obvious to me > how I could marshall a list of numbers to C. Surely it's possible > to create a ForeignObj, then fill it in element-by- element. But > isn't there a more straightforward way? Even without monads?
Here's some code from the Xlib interface: hslibs/xlib/Xlib.gc (This code is part of the HGL (http://haskell.org/graphics).) First, a function that wants a list of objects. Note that we use ListPoint (a type synonym we'll define below) instead of [Point]. The name 'ListPoint' triggers the appropriate kind of marshalling. Note too that the %call line contains: (listPoint arg4 arg4_size) That is, listPoint marshalling results in 2 arguments to the C function. > %fun XDrawPoints :: Display -> Drawable -> GC -> ListPoint -> CoordinateMode -> >IO () > %call (display arg1) (drawable arg2) (gC arg3) (listPoint arg4 arg4_size) >(coordinateMode arg5) > %code XDrawPoints(arg1,arg2,arg3,arg4,arg4_size,arg5) > %end free(arg4) Marshalling lists of points uses the functions marshallAddrList and unmarshallAddrList (defined later). > type ListPoint = [Point] > %dis listPoint x l = <<marshallAddrList allocPoints writePoint/unmarshallAddrList >readPoint>> (addr ({XPoint*} x)) (int l) To marshall a list of points we have to allocate some space in the C heap. Note that the size is scaled by the size of the objects. > %fun allocPoints :: Int -> IO Addr > %code res1 = (void*)malloc(sizeof(XPoint) * arg1) write points into an array > %fun writePoint :: Addr -> Int -> Point -> IO () > %call (addr ({XPoint*} s)) (int i) (point {s[i]}) > %code and read points from an array > %fun readPoint :: Addr -> Int -> IO Point > %call (addr ({XPoint*} s)) (int i) > %code > %result (point {s[i]}) These functions are useful with many different types of list. To marshall we: 1) Get the list length 2) Allocate an array that size in the C heap 3) Write values into the array. > marshallAddrList :: (Int -> IO Addr) -> (Addr -> Int -> a -> IO ()) -> [a] -> IO >(Addr, Int) > marshallAddrList alloc write as = do > let l = length as > arr <- alloc l > zipWithM_ (write arr) [0..] as > return (arr, l) To unmarshall we read values out. Freeing the array could be done here too but in this case it happens in the %end of the %fun that uses the array. It's a long time since I wrote this code so I can only guess that I thought this way would be more flexible. > unmarshallAddrList :: (Addr -> Int -> IO a) -> (Addr, Int) -> IO [a] > unmarshallAddrList read (ptr,l) = mapM (read ptr) [0..l-1] Points are defined in the usual way. I won't discuss this much since I think you just want Int or Floats or some such. > type Point = > ( Position -- x > , Position -- y > ) > %dis point x = declare {XPoint} x in > % ( position {(%x).x} > % , position {(%x).y} > % ) Hope this helps, -- Alastair Reid [EMAIL PROTECTED] http://www.cs.utah.edu/~reid/ _______________________________________________ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell