2012-05-08 17 views
1

私はFFIをpdflibに書いています。 Pdflib C APIには、さまざまなハンドル(ドキュメント、ページ、イメージ、フォント)を返す、および/またはプレーンな整数(ポインタではない)として返す関数が多数あります。newtype Int - > CInt marshaller

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

今私は、これらのタイプのためのマーシャラーを提供する必要があります:私は誤って私がの形でnewtypesの束を作成する機能に間違ったのparamを渡さないようにするために

見てのとおり、マーシャラーはまったく同じで、種類が異なるだけです。

私の質問は、ある種の魔法、SYB vodooのトリックがあります。これらの型を整列させるための関数を1つだけ使うことができますか、あるいは同じ関数を何度も書き直して別のnewtypeを作成する必要がありますか?

編集:私の問題を解決したので、私はドンの答えを受け入れました。私は

GeneralizedNewtypeDeriving 

に切り替え

は私のnewtypesのそれぞれに

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

を追加し、そして今私はマーシャルにそれらのすべてを標準fromIntegralを使用することができます。

ネイサンハウエルの答えも正しいです、私はそれをupvoted。しかし残念なことに、彼のソリューションは、私が使用しているc2hsのようなFFIプリプロセッサをあきらめることを意味します。

答えて

3

GeneralizedNewtypeDerivingを使用してタイプに「Num」を派生させることができます。これは、リテラルと演算子で少し役立ちます。

マーシャリングについては、htp2hsなどの新しいタイプのラップとアンラッピングを自動化できるFFI前処理を使用します。

from RWH

enter image description here

+0

おかげで、私はGeneralizedNewtypeDerivingをチェックします。私はc2hsを使用しています。そして、それは私が非組み込み型のためのマーシャラーを提供する必要があります。したがって、私の質問です。 –

7

GHCのFFIの拡張子は、そのラップ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 

また、(7.2.1以降で利用可能)新しいGHCジェネリック機能は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インスタンスを必要とせず、不透明なポインタ型には望ましくないようです。 –

関連する問題