[英]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.