[英]haskell FFI passing array of C structs in and out
I am trying to perform a series of transforms on graphical files using Haskell and Repa/DevIL. 我正在尝试使用Haskell和Repa / DevIL对图形文件执行一系列转换。 The starting example used was provided by the Haskell wiki page https://wiki.haskell.org/Numeric_Haskell:_A_Repa_Tutorial .
Haskell Wiki页面https://wiki.haskell.org/Numeric_Haskell:_A_Repa_Tutorial提供了使用的起始示例。 I am an imperative programmer of 30 years experience with some erlang for good measure, trying to learn Haskell outside a classroom environment.
我是一位具有30年经验的命令式程序员,从某种程度上讲,他很努力地尝试在课堂环境之外学习Haskell。
The problem is manipulating the data after the file load was first transformed into a Repa array: 问题是在文件加载首次转换为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)
which is successfully cast to type "Array F DIM3 Float" as output from the rgbTransform. 成功将其转换为类型“ Array F DIM3 Float”,作为rgbTransform的输出。 From that point on it has been a nightmare to use the data.
从那时起,使用数据一直是一场噩梦。 Flicking the array storage type between F(oreign) and U(nboxed) changes all following call's usability, plus the Repa-added monad layer IL forces use of liftM for nearly every equation following the 1st transform:
在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
These are the routines I can call without error. 这些是我可以正确调用的例程。 The IO monad's print command produces no output if placed in or after this 'let' list, due to the IL monad layer.
由于IL monad层的缘故,如果将IO monad的print命令放在此“ let”列表中或之后,则不会产生任何输出。
The game plan for the curious: 好奇的游戏计划:
I am looking for help with issues 4 and 5. 我正在寻求有关问题4和5的帮助。
4 -> The type system has been difficult to deal with while attempting to get C-usable memory pointers. 4->在尝试获取C可用的内存指针时,很难处理类型系统。 Going thru the mountains of haskell library calls has not helped.
穿过山顶的Haskell图书馆电话没有帮助。
5 -> The external C routine is of type: 5->外部C例程的类型为:
foreign import ccall unsafe "transform.h xform"
c_xform :: Ptr (CFloat,CFloat,CFloat) ->
CInt ->
IO ()
The Ptr is expected to point to an unboxed flat C array of rgb_t structs: Ptr预计指向rgb_t结构的拆箱平面C数组:
typedef struct
{
float r;
float g;
float b;
} rgb_t;
Available web-based FFI descriptions of how to deal with array pointers in FFI are non-existent if not downright obscure. 如果不是很晦涩的话,关于如何在FFI中处理数组指针的基于Web的FFI可用描述就不存在了。 The fairly straightforward idea of unfreezing and passing in a C array of floating-point RGB structs, modifying them in-place and then freezing the result is what I had in mind.
取消冻结并传递C数组的浮点RGB结构,就地修改它们,然后冻结结果的想法非常简单。 The external transform is pure in the sense that the same input will produce predictable output, does not use threads, does not use global vars nor depend upon obscure libraries.
外部转换是纯净的,因为相同的输入将产生可预测的输出,不使用线程,不使用全局var也不依赖于晦涩的库。
Foreign.Marshal.Array seems to provide a way to convert haskell data to C data and other way around. Foreign.Marshal.Array似乎提供了一种将haskell数据转换为C数据的方法。
I tested interfacing C code and haskell using the following files (Haskell + FFI for the first time for me) 我使用以下文件测试了接口C代码和haskell的配置(对我来说是首次Haskell + FFI)
hsc2hs rgb_ffi.hsc
ghc main.hs rgb_ffi.hs rgb.c
rgb.h 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 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 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 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.