newtype Int - > CInt marshaller

时间:2012-05-08 18:01:57

标签: haskell types

我正在向FFflib写FFI。 Pdflib C API有许多函数可以返回和/或将各种句柄(文档,页面,图像,字体)作为普通的整数(不是指针)。

为了确保我不会意外地将错误的参数传递给函数,我会以以下形式创建一堆新类型:

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技巧,我只能使用一个函数来编组所有这些类型,或者我是否必须为不同的新类型一次又一次地编写相同的函数?< / p> 编辑:我接受了唐的回答,因为它解决了我的问题。

我打开了

GeneralizedNewtypeDeriving 

添加了

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

我的每个新类型,现在我可以使用标准的积分来编组所有这些类型。

内森豪威尔的答案也是正确的,我赞同它。但不幸的是,他的解决方案意味着放弃FFI预处理器,比如我正在使用的c2hs。

2 个答案:

答案 0 :(得分:7)

GHC的FFI扩展允许使用包装FFI原语的newtypes。您可以更改导入的函数签名以使用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 Generics功能(自7.2.1开始提供)允许通用的解包和重新打包新类型:

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

答案 1 :(得分:3)

您可以使用GeneralizedNewtypeDeriving为您的类型派生'Num',这有助于您使用文字和运算符。

对于编组,我会使用FFI预处理,例如hsc2hs,它可以自动包装和展开新类型。

示例from RWH

enter image description here