haskell FFI将C结构的数组传入和传出

Cha*_*atz 0 c arrays struct haskell ffi

我正在尝试使用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)
Run Code Online (Sandbox Code Playgroud)

成功转换为输出"Array F DIM3 Float"作为rgbTransform的输出.从那时起,使用数据一直是一场噩梦.在F(oreign)和U(nboxed)之间轻击数组存储类型会改变所有后续调用的可用性,加上修复添加的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
Run Code Online (Sandbox Code Playgroud)

这些是我可以无错误地调用的例程.由于IL monad层,IO monad的print命令在放入此'let'列表中或之后不产生输出.

好奇的游戏计划:

  1. 阅读图形文件(通过Repa完成)
  2. 调整图像大小(未完成,不在修复中调整大小,必须手动编码)
  3. 转换并将图像从Word8转换为Float(完成)
  4. 得到一个Stablepointer到转换后的Float数据(未完成)
  5. 通过FFI(未完全完成)通过外部C例程将Float数据原样转换为{Float a,b,c;}的C结构数组.希望无需通过传递指向数据的指针来编组新的图形数组
  6. 对转换后的数据执行更多传递以提取更多信息(部分完成).

我正在寻找第4和第5个问题的帮助.

4 - >类型系统在尝试获取C可用内存指针时很难处理.穿过哈克尔图书馆电话的山脉并没有帮助.

5 - >外部C例程的类型为:

foreign import ccall unsafe "transform.h xform"
c_xform :: Ptr (CFloat,CFloat,CFloat) ->
           CInt ->
           IO ()
Run Code Online (Sandbox Code Playgroud)

预计Ptr将指向一个未装箱的扁平C阵列的rgb_t结构:

typedef struct
{
    float r;
    float g;
    float b;
} rgb_t;
Run Code Online (Sandbox Code Playgroud)

关于如何处理FFI中的数组指针的可用的基于Web的FFI描述如果不是完全模糊则不存在.解冻和传入一个浮点RGB结构的C数组,就地修改它们然后冻结结果这个相当简单的想法就是我想到的.外部变换是纯粹的,因为相同的输入将产生可预测的输出,不使用线程,不使用全局变量,也不依赖于模糊的库.

J.J*_*ala 5

Foreign.Marshal.Array似乎提供了一种将haskell数据转换为C数据和其他方式的方法.

我测试了使用以下文件连接C代码和haskell(我第一次使用Haskell + FFI)

hsc2hs rgb_ffi.hsc
ghc main.hs rgb_ffi.hs rgb.c
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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 ()
Run Code Online (Sandbox Code Playgroud)

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 ()
Run Code Online (Sandbox Code Playgroud)