You mean HaskellDirect doesn't work?

This is rather disappointing, and occupied a number of days of development time. The problem is that HaskellDirect, at least version 0.16, is really designed to expose C functions to Haskell rather than the other way around. It handles marshaling of primitive atomic values with panache, but generates this sort of code for marshaling the array of doubles:

Example 13-5. What HaskellDirect created for marshaling arrays in the beta_0 function (line numbers added for clarity)

1   beta_0_proxy :: [Prelude.Double]
2                -> [Prelude.Double]
3                -> Prelude.IO Prelude.Double
4   beta_0_proxy = wrap_beta_0 Regression.beta_0
5
6   foreign export  "beta_0" beta_0_proxy :: Addr.Addr -> Prelude.Int -> Addr.Addr -> Prelude.Int -> Prelude.IO Prelude.Double
7   wrap_beta_0 :: ([Prelude.Double] -> [Prelude.Double] -> Prelude.Double)
8               -> Addr.Addr
9               -> Prelude.Int
10              -> Addr.Addr
11              -> Prelude.Int
12              -> Prelude.IO Prelude.Double
13  wrap_beta_0 beta_0_meth xs len_xs ys len_ys =
14    case beta_0_meth xs
15                     ys of
16       o_beta_0 -> let
17                    len_xs = Prelude.id (Prelude.length xs)
18                   in
19                   do
20                     xs <- HDirect.marshalllist HDirect.sizeofDouble HDirect.writeDouble xs
21                     let len_ys = Prelude.id (Prelude.length ys)
22                     ys <- HDirect.marshalllist HDirect.sizeofDouble HDirect.writeDouble ys
23                     Prelude.return (o_beta_0)

To those unfamiliar with Haskell (such as the ePolyglot developers), the above resembles utter gibberish. It took some time (and careful studying of the Haskell compiler errors) to understand what was going on.

Look at line 6 in the above source code. What that line says is that GHC should export the function beta_0_proxy under the name "beta_0", taking arguments of (pointer, int, pointer, int), and returning a double. This makes sense so far, since we do indeed want a C-available function taking pointers and integers (the addresses of our arrays, and their length) and returning a double as a result.

But a quick look at the beta_0_proxy function shows a mismatch--its type signature takes two lists of doubles and returns a double, which is close--but not close enough for a typesafe compiler. It's easy enough to (by hand) change the type signature of beta_0_proxy to match, by editing the lines around lines 1-2 to match the type signature of the foreign export in line 6.

However, that's not the whole story. A look at lines 14-23 above shows some other peculiarities--notably, that HaskellDirect is valiantly trying to do the opposite of what we want--it's trying to marshal a list into an array of doubles, rather than unmarshaling an array of doubles into a Haskell list!

Some poring through the HaskellDirect library to reveal the correct functions (unmarshallist instead of marshallist, readDouble instead of writeDouble, etc.) and some careful hand-correction of the generated code results in the following:

Example 13-6. What we wanted for marshaling arrays in the beta_0 function

beta_0_proxy :: Addr.Addr
             -> Prelude.Int
             -> Addr.Addr
             -> Prelude.Int
             -> Prelude.IO Prelude.Double
beta_0_proxy = wrap_beta_0 Regression.beta_0

foreign export  "beta_0" beta_0_proxy :: Addr.Addr -> Prelude.Int -> Addr.Addr -> Prelude.Int -> Prelude.IO Prelude.Double
wrap_beta_0 :: ([Prelude.Double] -> [Prelude.Double] -> Prelude.Double)
            -> Addr.Addr
            -> Prelude.Int
            -> Addr.Addr
            -> Prelude.Int
            -> Prelude.IO Prelude.Double
wrap_beta_0 beta_0_meth xs len_xs ys len_ys = do
                xs <- HDirect.unmarshalllist HDirect.sizeofDouble 0 (Word.intToWord32 len_xs) HDirect.readDouble xs
                ys <- HDirect.unmarshalllist HDirect.sizeofDouble 0 (Word.intToWord32 len_ys) HDirect.readDouble ys
                case beta_0_meth xs ys of
                        o_beta_0 -> Prelude.return( o_beta_0 )

The code compiles. A quick test with a C stub program shows that the exported functions are indeed available from C. The HaskellDirect library is up to the challenge of exporting the functions, but the automatically-generated code from ihc requires laborious by-hand corrections to work properly, meaning that while this process can be made to work, it is not ready for production yet.