10
$\begingroup$

Looking for a way to call a Haskell DLL from Mathematica, I've stumbled on this, for GNU R:

http://neilmitchell.blogspot.com.br/2011/10/calling-haskell-from-r.html

It is (to me) a beautiful example and I managed to make it work on Mathematica without modification through this spell:

Needs["NETLink`"]
hsStart = DefineDLLFunction["HsStart", "c:\\temp\\SumRoots.dll", "void", {}];
hsEnd = DefineDLLFunction["HsEnd", "c:\\temp\\SumRoots.dll", "void", {}];
sroot = DefineDLLFunction["sumRootsR", "c:\\temp\\SumRoots.dll", "double", {"int*", "double[]", "double*"}];
hsStart[];
resulta = 0;
lista = {9, 3.5, 5.58, 64.1, 12.54};
sroot[Length[lista], lista, resulta];
resulta
18.7805
hsEnd[];

Then I tried to modify the example to return a vector of doubles, instead of a single value:
Code in Haskell:

-- SumRoots.hs

{-# LANGUAGE ForeignFunctionInterface #-}
module SumRoots where

import Foreign

foreign export ccall acumSumR :: Ptr Int -> Ptr Double -> Ptr Double -> IO ()

acumSum :: [Double] -> [Double]
acumSum xs = scanl (\x y -> x+y) 0 xs

acumSumR :: Ptr Int -> Ptr Double -> Ptr Double -> IO ()
acumSumR n xs result = do
                       n <- peek n
                       xs <- peekArray n xs
                       pokeArray result $ acumSum xs

Code in C: (exactly the same of the mentioned blog post)

Compiling:

ghc -c SumRoots.hs
ghc -c StartEnd.c
ghc -shared -o SumRoots.dll SumRoots.o StartEnd.o

Code in Mathematica:

Needs["NETLink`"]
hsStart = DefineDLLFunction["HsStart", "c:\\temp\\SumRoots.dll", "void", {}];
hsEnd = DefineDLLFunction["HsEnd", "c:\\temp\\SumRoots.dll", "void", {}];
acums = DefineDLLFunction["acumSumR", "c:\\temp\\SumRoots.dll", "double[]", {"int*", "double[]", "double[]"}];
hsStart[];
lista = {9, 3.5, 5.58, 64.1, 12.54};
NETBlock@Module[{n, resultb}, n = Length[lista]+1; 
  resultb = NETNew["System.Double[]", n]; acums[n, lista, resultb]; 
  NETObjectToExpression[resultb]]

{0., 0., 0., 0., 0., 0.}

The result should be {0.0, 9.0, 12.5, 18.08, 82.18, 94.72}. I'm not sure if this problem belongs to Mathematica or Haskell realm, but posting here is based on the fact that the GNU R call worked:

dyn.load("C:/temp/SumRoots.dll") 
.C("HsStart")
acumSum <- function(input)
{
return(.C("acumSumR", n=as.integer(length(input)), xs=as.double(input), result=as.double(rep(0,length(input)+1)))$result)
}
input <- c(9,3.5,5.58,64.1,12.54)
acumSum(input)

So, can somebody give a hint on how to call this modified Haskell DLL function from Mathematica?
Environment:
SO: Windows 10 64-bit
Mathematica 8.0 64-bit
Haskell Platform 8.0.1 64-bit
GNU R 3.3.2 64-bit

Cheers,

Rand

$\endgroup$
12
$\begingroup$

The problem lies in the declaration of the DLL function acumSumR. It is declared to return a double[] but the Haskell return type is IO () which corresponds to C void. So the declaration should read:

acums =
  DefineDLLFunction["acumSumR"
  , "c:\\temp\\SumRoots.dll"
  , "void"                           (* <-- "void" instead of "double[]" *)
  , {"int*", "double[]", "double[]"}
  ];

With this change, the expected result is obtained.

$\endgroup$
  • $\begingroup$ I Copy-Pasted your code to mine, however the result was the same. Could it be a configuration problem? Or maybe another way to call the acums function? $\endgroup$ – rand Jan 8 '17 at 15:17
  • $\begingroup$ I called acums using the code you exhibit. For me, both V8 and V11 give the same results: all zeros with double[] and the expected results for void. With double[] I also get a .NET exception complaining about invalid marshalling. Do you see that exception? I also get the same results (including warning message) whether I use .NET 2.0 or 4.6. I am on Win7 instead of Win10, but otherwise I am using the same versions as you. $\endgroup$ – WReach Jan 8 '17 at 19:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.