2013-10-15 3 views
0

У меня есть функция, написанная на C Я бы хотел позвонить из программы Haskell. Тип Функция:Передача списка различных типизированных элементов функции C

foo :: Int -> Ptr a -> IO() 

Он принимает размер и указатель на то, что и помещает все это где-то в памяти. Он предназначен для использования со смешанными типами. Вы можете поместить n float, затем m bools и т. Д. (В C).

Самый удобный способ представить такую ​​ситуацию в Haskell - на мой взгляд - что-то вроде ([a],[b]), например. Но мне нужно все, чтобы поместиться в Ptr a (это фактически пустота * в C). Я могу попытаться написать такую ​​функцию, как ([a],[b]) -> Ptr c, но мне нужна помощь. Желаемая конечная функция будет:

withArrayLen magicArray foo 
+0

Прочитать интерфейс внешних функций и как записать хранимый экземпляр для типов данных. – Satvik

ответ

1

вещь, которые могут быть сохранены в памяти, является экземпляры типа класса StorableForeign.Storable). Таким образом, учитывая Необработанному FFI прототип

foreign import "foo" c_foo :: CInt -> Ptr a -> IO() 

вы могли бы написать что-то подобное для однородных списков:

homfoo :: Storable a => [a] -> IO() 
homfoo items = withArray items $ \ptr -> c_foo (fromIntegral len) ptr 
    where len = length items * sizeOf (head items) 

Но вы сказали, что функция предназначена для работы со смешанными типами, поэтому нам нужны тип гетерогенного списка с ограниченным типом для красивой обертки Haskell. Вот один из способов сделать это:

{-# LANGUAGE GADTs #-} 

data DynStorable where 
    MkStorable :: Storable a => a -> DynStorable 

foo :: [DynStorable] -> IO() 
foo items = 
    let (requiredSize, offsets) = mapAccumL sizeFold 0 items in 
    allocaBytes requiredSize $ \ptr -> do 
     zipWithM 
      (\offset (MkStorable x) -> pokeByteOff ptr offset x) 
      offsets items 
     c_foo (fromIntegral requiredSize) ptr 
    where 
    sizeFold offset (MkStorable x) = 
     let unalignment = offset `mod` alignment x 
      offset' = if unalignment /= 0 
       then offset + alignment x - unalignment 
       else offset 
     in (offset' + sizeOf x, offset') 

main :: IO() 
main = do 
    foo [MkStorable (2 :: Int), MkStorable (3.0 :: Double), MkStorable True] 

функция C не имеет средств, чтобы различать границы записи в принимаемых порциях данных, но это не было бы трудно включить префиксы длины или коды типа, если это необходимо.

Смежные вопросы