[英]haskell FFI passing array of C structs in and out
我正在尝试使用Haskell和Repa / DevIL对图形文件执行一系列转换。 Haskell Wiki页面https://wiki.haskell.org/Numeric_Haskell:_A_Repa_Tutorial提供了使用的起始示例。 我是一位具有30年经验的命令式程序员,从某种程度上讲,他很努力地尝试在课堂环境之外学习Haskell。
问题是在文件加载首次转换为Repa数组后处理数据:
import Data.Array.Repa.IO.DevIL (runIL,readImage,writeImage,Image(RGB),IL)
import qualified Data.Array.Repa as R
import Data.Vector.Unboxed as DVU
import Control.Monad
main :: IO ()
main = do
[f] <- getArgs
(RGB a) <- runIL $ Data.Array.Repa.IO.DevIL.readImage f
let
c = (computeP (R.traverse a id rgbTransform)) :: IL (Array U DIM3 Float)
成功将其转换为类型“ Array F DIM3 Float”,作为rgbTransform的输出。 从那时起,使用数据一直是一场噩梦。 在F(oreign)和U(nboxed)之间轻拂数组存储类型会更改所有后续调用的可用性,加上添加Repa的monad层IL会强制对一次转换后的几乎每个方程使用liftM:
let -- continued
sh = liftM R.extent c -- IL DIM3
v = liftM R.toUnboxed c -- IL (Vector Float)
lv = liftM DVU.length v -- IL Int
f = liftM indexed v -- vector of tuples: (Int,a) where Int is idx
k = (Z :. 2) :. 2 :. 0 :: DIM3
这些是我可以正确调用的例程。 由于IL monad层的缘故,如果将IO monad的print命令放在此“ let”列表中或之后,则不会产生任何输出。
好奇的游戏计划:
我正在寻求有关问题4和5的帮助。
4->在尝试获取C可用的内存指针时,很难处理类型系统。 穿过山顶的Haskell图书馆电话没有帮助。
5->外部C例程的类型为:
foreign import ccall unsafe "transform.h xform"
c_xform :: Ptr (CFloat,CFloat,CFloat) ->
CInt ->
IO ()
Ptr预计指向rgb_t结构的拆箱平面C数组:
typedef struct
{
float r;
float g;
float b;
} rgb_t;
如果不是很晦涩的话,关于如何在FFI中处理数组指针的基于Web的FFI可用描述就不存在了。 取消冻结并传递C数组的浮点RGB结构,就地修改它们,然后冻结结果的想法非常简单。 外部转换是纯净的,因为相同的输入将产生可预测的输出,不使用线程,不使用全局var也不依赖于晦涩的库。
Foreign.Marshal.Array似乎提供了一种将haskell数据转换为C数据的方法。
我使用以下文件测试了接口C代码和haskell的配置(对我来说是首次Haskell + FFI)
hsc2hs rgb_ffi.hsc
ghc main.hs rgb_ffi.hs rgb.c
rgb.h
#ifndef RGB_H
#define RGB_H
#include <stdlib.h>
typedef struct {
float r;
float g;
float b;
} rgb_t;
void rgb_test(rgb_t * rgbs, ssize_t n);
#endif
rgb.h
#include <stdlib.h>
#include <stdio.h>
#include "rgb.h"
void rgb_test(rgb_t * rgbs, ssize_t n)
{
int i;
for(i=0; i<n; i++) {
printf("%.3f %.3f %.3f\n", rgbs[i].r, rgbs[i].g, rgbs[i].b);
rgbs[i].r *= 2.0;
rgbs[i].g *= 2.0;
rgbs[i].b *= 2.0;
}
}
rgb_ffi.hsc
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE CPP #-}
module RGB where
import Foreign
import Foreign.C
import Control.Monad (ap)
#include "rgb.h"
data RGB = RGB {
r :: CFloat, g :: CFloat, b :: CFloat
} deriving Show
instance Storable RGB where
sizeOf _ = #{size rgb_t}
alignment _ = alignment (undefined :: CInt)
poke p rgb_t = do
#{poke rgb_t, r} p $ r rgb_t
#{poke rgb_t, g} p $ g rgb_t
#{poke rgb_t, b} p $ b rgb_t
peek p = return RGB
`ap` (#{peek rgb_t, r} p)
`ap` (#{peek rgb_t, g} p)
`ap` (#{peek rgb_t, b} p)
foreign import ccall "rgb.h rgb_test" crgbTest :: Ptr RGB -> CSize -> IO ();
rgbTest :: [RGB] -> IO [RGB]
rgbTest rgbs = withArray rgbs $ \ptr ->
do
crgbTest ptr (fromIntegral (length rgbs))
peekArray (length rgbs) ptr
rgbAlloc :: [RGB] -> IO (Ptr RGB)
rgbAlloc rgbs = newArray rgbs
rgbPeek :: Ptr RGB -> Int -> IO [RGB]
rgbPeek rgbs l = peekArray l rgbs
rgbTest2 :: Ptr RGB -> Int -> IO ()
rgbTest2 ptr l =
do
crgbTest ptr (fromIntegral l)
return ()
main.hs
module Main (main) where
import RGB
main =
do
let a = [RGB {r = 1.0, g = 1.0, b = 1.0},
RGB {r = 2.0, g = 2.0, b = 2.0},
RGB {r = 3.0, g = 3.0, b = 3.0}]
let l = length a
print a
-- b <- rgbTest a
-- print b
c <- rgbAlloc a
rgbTest2 c l
rgbTest2 c l
d <- rgbPeek c l
print d
return ()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.