簡體   English   中英

haskell FFI傳入和傳出C結構數組

[英]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”列表中或之后,則不會產生任何輸出。

好奇的游戲計划:

  1. 讀取圖形文件(通過Repa完成)
  2. 調整圖像大小(未完成,在Repa中未調整大小,必須手工編碼)
  3. 將圖像從Word8轉換並轉換為Float(完成)
  4. 獲取轉換后的Float數據的穩定指針(未完成)
  5. 通過外部C例程通過FFI將{Float a,b,c;}的C結構數組原位轉換為Float數據(未完全完成)。 希望通過傳遞指向數據的指針而無需編組新的圖形數組來完成此操作
  6. 對轉換后的數據執行更多傳遞以提取更多信息(部分完成)。

我正在尋求有關問題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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM