2012-05-08 39 views
1

我在寫pdfIib給FFI。 Pdflib C API有許多函數返回和/或採用各種句柄(文檔,頁面,圖像,字體)爲純整數(而不是指針)。newtype Int - > CInt marshaller

爲了保證我不小心錯PARAM傳遞給我的形式創建一批newtypes的功能:

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 

正如你所看到的marshallers是完全一樣的,只是爲了不同的類型。

所以我的問題是,是否有某種類型的魔術,SYB vodoo技巧,我可以使用只有一個函數來編組所有這些類型,或者是否必須一次又一次地爲不同的newtypes編寫相同的函數?

編輯:我接受唐的回答,因爲它解決了我的問題。

我對

GeneralizedNewtypeDeriving 

切換添加

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

每個我newtypes的,現在我可以使用標準fromIntegral馬歇爾所有的人。

內森豪威爾的答案也是正確的,我upvoted它。但不幸的是,他的解決方案意味着放棄FFI預處理器,如我正在使用的c2hs。

回答

3

您可以使用GeneralizedNewtypeDeriving爲您的類型派生'Num',這可以幫助您瞭解文字和操作符。

對於編組,我會使用FFI預處理,如hsc2hs,它可以自動化新類型的包裝和解包。

一個例子from RWH

enter image description here

+0

謝謝,我會檢查GeneralizedNewtypeDeriving。我正在使用c2hs。它需要我爲任何非內建類型提供編組器。因此我的問題。 –

7

GHC的FFI擴展允許使用newtypes那套FFI元。您可以更改導入的函數簽名以使用newtypes,並且(希望)可以避免必須手動打開它們。

{-# 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 

另外,新GHC泛型功能(自7.2.1可以)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實例,它們對於不透明的指針類型似乎是不可取的。 –