2014-09-18 3 views
4

구조체를 사용하여 동일한 구조체를 반환하는 C 함수를 사용하기 위해 FFI를 사용하고 있습니다. 내가 본 레퍼런스는이 구조체를 하스켈로 가져 오기 위해이 구조체에 대한 포인터를 사용해야한다고 말한다. 그래서 예를 들면.하스켈 - 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() 및 서명 보관 가능한 A =>를 가지고있는,을 사용 - (-> IO의 B의 PTR A) ->를 확인했다 B> IO를, 왜냐하면 그들은 main 함수 내부에서 함수를 호출하기 때문입니다.

그러나, 나는 형 바의 기능을 점점 도서관에서이 기능을 포장하고 싶습니다 -> IO없이 바, 그것은 unsafePerformIO없이 할 수 있습니까? 절차가 뭐니?

+0

경우 :

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

을하고 마지막으로

f_wrap_foo :: BarPtr -> IO() 

로 가져, 당신과이 수입 함수를 호출 할 것 'Ptr A -> IO()'와 같은 순수한 함수를 원한다면, 대응하는 C 함수는 by가 가리키는 메모리를 수정하는 것만 큼 의미있는 "거의 순수"해야합니다. 이 경우, Storable과'alloca'를 사용하여 C에 대한 포인터를 생성 한 다음 그 포인터에서 읽고 값을 반환함으로써'A -> A '유형의 함수를 작성합니다. 이 함수는 관찰 할 수있는 효과가 없으므로 도덕적으로 순수하므로'unsafePerformIO'를 호출하는 것이 완벽합니다 (사실 이것은 unsafePerformIO의 의도 된 사용입니다) – user2407038

답변

5

unsafePerformIO을 사용하지 않고 IO을 제거 할 수 없습니다. 그러나이 경우 원하는 유형의 함수를 얻을 수 있으며 몇 가지주의 사항이 있습니다. 특히 C 함수 "foo"는 전역 변수, 스레드 로컬 상태 또는 단일 인수 외에는 아무 것도 의존 할 수 없습니다. 또한 을 호출하면 bar이 변경되지 않은 경우 항상 동일한 결과를 제공해야합니다.

나는 때문에 결과 유형이 호출

f_foo :: BarPtr -> BarPtr 

컴파일러 오류가 발생합니다 함께 C 함수를

bar foo(bar input); 

를 가져 오는 것으로 기대합니다. 난 당신이 (C에서) 래퍼 함수 작성해야 할 것 같아요 :

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

테스트되고 승인되었습니다! 고맙습니다! – guaraqe