2012-05-08 4 views
1

나는 pdflib에 FFI를 쓰고있다. Pdflib C API는 다양한 핸들 (document, page, image, font)을 일반 Integer (포인터가 아님)로 반환하거나 가져가는 많은 기능을 가지고 있습니다.newtype Int -> CInt marshaller

내가 실수로 난의 형태로 newtypes의 무리를 생성 함수에 잘못된 PARAM을 통과하지 않도록하기 위해서 :

newtype PdiDoc = PdiDoc Int 
newtype PdiPage = PdiPage Int 
newtype PdfImage = PdfImage Int 
newtype PdfFont = PdfFont Int 

지금 나는 그 유형에 대한 마샬를 제공해야합니다.

image2c (PdfImage i) = fromIntegral i 
font2c (PdfFont f) = fromIntegral f 
pdipage2c (PdiPage i) = fromIntegral i 

마샬 러는 다른 유형의 경우와 완전히 동일합니다.

내 질문에, 어떤 종류의 마술, SYB vodoo 트릭을 사용하여 모든 형식을 마샬링하는 데 하나의 기능을 사용할 수 있습니까? 아니면 여러 가지 새로운 형식에 대해 동일한 기능을 반복해서 작성해야합니까?

편집 : 내 문제를 해결했기 때문에 Don의 대답을 받아 들였습니다.

내가

GeneralizedNewtypeDeriving 

에 전환 내 newtypes 각각

deriving (Eq, Ord, Num, Enum, Real, Integral) 

을 추가하고, 지금은 마샬에 그들 모두를 표준 fromIntegral를 사용할 수 있습니다.

Nathan Howell의 답변도 정확합니다. 나는 그것을 upvoted. 하지만 불행히도 그의 솔루션은 내가 사용하는 c2hs와 같은 FFI 전 처리기를 포기해야 함을 의미합니다.

답변

3

GeneralizedNewtypeDeriving을 사용하여 유형에 '숫자'를 도출 할 수 있습니다. 이는 리터럴 및 연산자에 도움이됩니다.

마샬링을 위해 htp2hs와 같은 FFI 전처리를 사용하여 newtyp의 래핑과 래핑을 자동화 할 수 있습니다.

from RWH :

enter image description here

+0

덕분에, 내가 GeneralizedNewtypeDeriving를 확인할 수 있습니다 :

{-# LANGUAGE ForeignFunctionInterface #-} module Main where newtype Foo = Foo Int foreign import ccall someCall :: Foo -> IO Foo main :: IO() main = do Foo x <- someCall (Foo 1) print x 

또는 (7.2.1 이후 사용 가능) 새로운 GHC 제네릭 기능은 newtypes의 일반적인 포장 풀기 및 재 포장을 할 수 있습니다. 나는 c2hs를 사용하고있다. 그리고 비 내장 유형에 대한 마샬 러를 제공해야합니다. 그러므로 내 질문. –

7

GHC의 FFI 확장이 그 랩 FFI 프리미티브 newtypes를 사용 할 수 있습니다. 가져온 함수 시그니처를 변경하여 newtypes를 사용할 수 있으며 수동으로 언팩해야하는 것을 피할 수 있습니다.

{-# LANGUAGE DeriveGeneriC#-} 
{-# LANGUAGE ForeignFunctionInterface #-} 
{-# LANGUAGE TypeFamilies #-} 

module Main where 

import GHC.Generics 

-- use a regular newtype 
newtype Foo1 = Foo1 Int deriving (Generic, Show) 

-- or with record syntax 
newtype Foo2 = Foo2{foo2 :: Int} deriving (Generic, Show) 

unpack :: (Generic a, Rep a ~ D1 dc (C1 cc (S1 sc (K1 R kc)))) => a -> kc 
unpack = unK1 . unM1 . unM1 . unM1 . from 

pack :: (Generic a, Rep a ~ D1 dc (C1 cc (S1 sc (K1 R kc)))) => kc -> a 
pack = to . M1 . M1 . M1 . K1 

-- the C import uses Ints 
foreign import ccall "someCall" c'someCall :: Int -> IO Int 

-- and the typed wrapper packs/unpacks to FFI primitives 
someCall :: Foo1 -> IO Foo2 
someCall = fmap pack . c'someCall . unpack 

main :: IO() 
main = do 
    Foo2 x <- someCall (Foo1 1) 
    print x 
+0

나는 c2hs를 사용하고있다. 그리고 비 내장 유형에 대한 마샬 러를 제공해야합니다. 마샬 러없이 타입을 사용하도록 c2hs에게 지시하는 방법이 있습니까? –

+0

@VagifVerdi 나는 결코 c2hs를 사용하지 않았기 때문에 확실하지 않습니다. 그들은 newtype 키워드를 가지고있는 것처럼 보이지만 그것은 포인터가 아니라 원시 타입과 함께 사용되는 것으로 보인다. –

+0

@VagifVerdi 대체 솔루션으로 내 대답을 업데이트했습니다. 그것은 Num/Integral 인스턴스를 필요로하지 않으며, 불투명 한 포인터 타입에 바람직하지 않은 것처럼 보입니다. –