2014-09-18 4 views
4

Я использую FFI для использования функции в C, которая берет структуру и возвращает ту же структуру. Ссылки, которые я видел, говорят, что я должен использовать указатели на эти структуры, чтобы иметь возможность импортировать их в Haskell. Так, например.Haskell - FFI и указатели

data Bar = Bar { a :: Int, b :: Int } 
type BarPtr = Ptr (Bar) 

foreign import ccall "static foo.h foo" 
    f_foo :: BarPtr -> BarPtr 

Теперь у меня есть проблема с тем, что я должен использовать эту функцию. references я видел, были функции типа BarPtr -> IO() и используется с, который имеет подпись Storable а => а -> (PTR а -> IO б) -> IO б, что было хорошо , потому что они вызывают функцию внутри main.

Однако, я хотел бы, чтобы обернуть эту функцию в библиотеке, получить функцию типа Bar -> Бар без IO, можно обойтись без unsafePerformIO? Какая процедура?

+0

Если вам нужна чистая функция от чего-то типа «Ptr A -> IO()», тогда соответствующая функция C должна быть «почти чистой» в том смысле, что единственным ее эффектом является изменение памяти, на которую указывает аргумент. Если это так, вы пишете функцию типа 'A -> A', используя Storable и' alloca', чтобы создать указатель для C, затем считывая с этого указателя и возвращая значение. Эта функция нравственно чиста, так как она не имеет наблюдаемого эффекта, поэтому называть «unsafePerformIO» на ней совершенно нормально (на самом деле это предполагаемое использование unsafePerformIO) – user2407038

ответ

5

Невозможно удалить IO из этого типа без использования unsafePerformIO. Однако в этом случае можно получить функцию с типом, который вы хотите, с некоторыми оговорками. В частности, функция C «foo» не может зависеть от каких-либо глобальных переменных, ните-локального состояния или чего-либо другого, кроме единственного аргумента. Кроме того, вызов foo(bar) должен всегда обеспечивать тот же результат, когда bar не изменяется.

Я ожидаю, что попытка импортировать функции С

bar foo(bar input); 

с этим вызовом

f_foo :: BarPtr -> BarPtr 

приведет к ошибке компиляции из-за типа результата. Я думаю, что вам, возможно, придется написать функцию-обертки (в C):

void wrap_foo(bar *barPtr) { 
    bar outp = foo(*barPtr); 
    *barPtr = outp; 
} 

и импортировать его как

f_wrap_foo :: BarPtr -> IO() 

Наконец, вы могли бы назвать эту импортируемую функцию с:

fooBar :: Bar -> Bar 
fooBar bar = unsafePerformIO $ with bar $ \barPtr -> do 
    f_wrap_foo barPtr 
    peek barPtr 
+0

Протестировано и одобрено! Спасибо! – guaraqe

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