
IO ()
From Haskell, I want to call a C function that returns a struct by value (rather than, say, returning a pointer). For example: typedef struct { double x; double y; } point_t; point_t polar(double theta); I can create a Haskell type Point and make it an instance of Storable easily enough: data Point = Point CDouble CDouble instance Storable Point where -- insert obvious code here And now I want to do something like this: foreign import ccall unsafe polar :: CDouble -> IO Point ...but that doesn't appear to be legal (at least in GHC 6.12). Is there any way to import this C function into Haskell _without_ having any additional wrapper C code? I mean, I suppose I could write something like: // C: void polar_wrapper(double theta, point_t* output) { *output = polar(theta); } -- Haskell: foreign import ccall unsafe polar_wrapper :: CDouble -> Ptr Point - polar :: CDouble -> IO Point polar theta = do -- insert obvious code here ...but that's a lot of extra boilerplate if I have many such functions to wrap, and it seems like GHC should be able to do that sort of thing for me. P-: Cheers, -Matt

On 2011-05-25 16:19 -0400, Matthew Steele wrote:
From Haskell, I want to call a C function that returns a struct by value (rather than, say, returning a pointer). For example:
typedef struct { double x; double y; } point_t; point_t polar(double theta);
I can create a Haskell type Point and make it an instance of Storable easily enough:
data Point = Point CDouble CDouble instance Storable Point where -- insert obvious code here
Note that there may be an arbitrary amount of padding bytes between the two members of your struct, as well as after the last member, so defining this Storable instance portably is somewhat tricky and non-obvious.
And now I want to do something like this:
foreign import ccall unsafe polar :: CDouble -> IO Point
...but that doesn't appear to be legal (at least in GHC 6.12). Is there any way to import this C function into Haskell _without_ having any additional wrapper C code?
No, the Haskell FFI simply cannot describe C functions with struct parameters or return values. You will need to call this function with a C wrapper. Assuming you got the Storable instance correct, something like void wrap_polar(double theta, point_t *out) { *out = polar(theta); } should do nicely. Alternately, you can avoid the tricky business of defining a Storable instance for your struct entirely with something like: void wrap_polar(double theta, double *x, double *y) { point_t tmp = polar(theta); *x = tmp.x; *y = tmp.y; } Cheers, -- Nick Bowler, Elliptic Technologies (http://www.elliptictech.com/)
participants (2)
-
Matthew Steele
-
Nick Bowler