HaskellHaskell12CHaskell

 COSAPICCHaskellFFIHaskellC

C


 22HaskellFFICPtrC使Ptr使HaskellC

 Storable

 baseForeign.Marshal.ArrayC

 mallocArrayC

-- |Allocate storage for the given number of elements of a storable type
-- (like 'Foreign.Marshal.Alloc.malloc', but for multiple elements).
--
mallocArray :: Storable a => Int -> IO (Ptr a)
mallocArray  = doMalloc undefined
  where
    doMalloc            :: Storable a' => a' -> Int -> IO (Ptr a')
    doMalloc dummy size  = mallocBytes (size * sizeOf dummy)


 CpeekArraypokeArray

-- marshalling
-- -----------

-- |Convert an array of given length into a Haskell list.  The implementation
-- is tail-recursive and so uses constant stack space.
--
peekArray          :: Storable a => Int -> Ptr a -> IO [a]
peekArray size ptr | size <= 0 = return []
                 | otherwise = f (size-1) []
  where
    f 0 acc = do e <- peekElemOff ptr 0; return (e:acc)
    f n acc = do e <- peekElemOff ptr n; f (n-1) (e:acc)



-- |Write the list elements consecutive into memory
--
pokeArray :: Storable a => Ptr a -> [a] -> IO ()
#ifndef __GLASGOW_HASKELL__
pokeArray ptr vals =  zipWithM_ (pokeElemOff ptr) [0..] vals
#else
pokeArray ptr vals0 = go vals0 0#
  where go [] _          = return ()
        go (val:vals) n# = do pokeElemOff ptr (I# n#) val; go vals (n# +# 1#)
#endif


 peekArrayCHaskellpokeArrayHaskellC

 CCmallocArraypeekArraypokeArrayArrayCStrorable使CHaskellStorableC

 HaskellCInt使fromIntegral使IntCInt64OS32int

Array.hs:

import Control.Exception     ( bracket )
import Foreign.C.Types       ( CInt(..) )
import Foreign.Marshal.Alloc ( free )
import Foreign.Marshal.Array
import Foreign.Storable      ( Storable(..) )
import Foreign.Ptr           ( Ptr(..) )

useAsCArray :: Storable a => [a] -> (Ptr a -> IO b) -> IO b
useAsCArray list process
  = bracket
      -- リストをCの配列に変換
      (do carr <- mallocArray len
          pokeArray carr list
          -- carr <- newArray list
          return carr)
       -- Cの配列を開放
      free
      -- Cの配列を利用して処理
      process
  where len = length list

main :: IO ()
main = do
    let xs :: [CInt]
        xs  =  [0..9]
        len = length xs
    ys <- useAsCArray xs $ \carr -> do
              -- Cの配列を扱う関数を利用
              cUpdateArray carr 4 (fromIntegral len)
              -- 処理の結果を読み込み
              peekArray len carr
    print ys

foreign import ccall "updateArray" cUpdateArray :: Ptr CInt -> CInt -> CInt -> IO ()


carray.h:

void updateArray ( int*, int, int );


carray.c:

#include "carray.h"

void updateArray ( int *xs, int y, int len ) {
  int i;
  for (i = 0; i < len; i++) {
    xs[i] = xs[i] + y;
  };
}




$ ghc carray.h carray.c Array.hs
Linking Array ...
$ ./Array
[4,5,6,7,8,9,10,11,12,13]


 C使CuseAsCArray使mallocArraypokeArrayHaskellCmain使peekArrayCHaskell

 HaskellC使HaskellC使mallocArraypokeArray使CCCCpeekArray

 HaskellC使HaskellCCForeign.Marshal.ArrayHaskellC

-- |Temporarily store a list of storable values in memory
-- (like 'Foreign.Marshal.Utils.with', but for multiple elements).
--
withArray :: Storable a => [a] -> (Ptr a -> IO b) -> IO b
withArray vals = withArrayLen vals . const

-- |Like 'withArray', but the action gets the number of values
-- as an additional parameter
--
withArrayLen :: Storable a => [a] -> (Int -> Ptr a -> IO b) -> IO b
withArrayLen vals f  =
  allocaArray len $ \ptr -> do
      pokeArray ptr vals
      res <- f len ptr
      return res
  where
    len = length vals


 Foreign.Marshal.ArrayuseAsCArraywithArraywithArrayLenwithArrayLenCCwithArraywithArrayLen使

 useAsCArraywithArray/withArrayLenuseAsCArraybracketHaskellC使C使mallocmallocArraywithArray/withArrayLenallocaallocaArrayHaskell12

 withArraywithArrayLen使C使

import Foreign.C.Types       ( CInt(..) )
import Foreign.Marshal.Array
import Foreign.Ptr           ( Ptr(..) )

main :: IO ()
main = do
    let xs :: [CInt]
        xs  = [0..9]
        len = length xs
    ys <- withArray xs $ \carr -> do
    -- ys <- withArrayLen xs $ \len carr -> do
              cUpdateArray carr 4 (fromIntegral len)
              peekArray len carr
    print ys

foreign import ccall "updateArray" cUpdateArray :: Ptr CInt -> CInt -> CInt -> IO ()




$ ghc carray.h carray.c Array.hs
Linking Array ...
$ ./Array
[4,5,6,7,8,9,10,11,12,13]