Here is an example. The
floorfrac function takes a list of numbers and returns a pair of two lists. The first list of the pair has type
[Int] and the second one has type
[Double].
To make the function compatible with R, returning a list of two vectors, these two vectors must have the same type. Hence I use
fromIntegral to convert the
[Int] list.
import qualified Data.Vector.SEXP as DV
floorfrac :: [Double] -> ([Int], [Double])
floorfrac xs = (integerParts, fractionalParts)
where integerParts = map floor xs
fractionalParts = zipWith (-) xs (map fromIntegral integerParts)
foreign export ccall floorfracR :: Ptr CDouble -> Ptr CInt -> Ptr (SEXP s R.Real) -> IO()
floorfracR :: Ptr CDouble -> Ptr CInt -> Ptr (SEXP s R.Real) -> IO()
floorfracR xs n result = do
n <- peek n
xs <- peekArray (fromIntegral n :: Int) xs
let (integerParts, fractionalParts) = floorfrac $ map realToFrac xs
pokeArray result $ map (DV.toSEXP . DV.fromList) [map fromIntegral integerParts, fractionalParts]
In summary:
- create two lists of numbers of the same type, create a list containing these two lists
- map DV.toSEXP . DV.fromList to this list
- use pokeArray
To invoke the function in R, once you get the compiled library:
> dyn.load("FloorFrac.so")
> .C("HsStart")
list()
> input <- c(1.5, 2.6)
> .C("floorfracR", xs=as.double(input), n=length(input), result=list(0,0))$result
[[1]]
[1] 1 2
[[2]]
[1] 0.5 0.6
Note that the result argument must be given as a list whose length is the number of vectors of the output.