Haskell 新类型Int->;辛特马歇尔勒

Haskell 新类型Int->;辛特马歇尔勒,haskell,types,Haskell,Types,我正在给pdflib写FFI。Pdflib C API有很多函数,它们返回和/或将各种句柄(文档、页面、图像、字体)作为纯整数(而不是指针)使用 为了确保不会意外地将错误的参数传递给函数,我创建了一组新类型,其形式如下: newtype PdiDoc = PdiDoc Int newtype PdiPage = PdiPage Int newtype PdfImage = PdfImage Int newtype PdfFont = PdfFont Int 现在我需要为这些类型提供封送拆收器

我正在给pdflib写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
正如您所看到的,封送处理程序完全相同,只是用于不同的类型

所以我的问题是,是否有某种类型魔术,SYB-vodoo技巧,我可以用它来只有一个函数来马歇尔所有这些类型,还是我必须为不同的新类型一次又一次地编写相同的函数

编辑:我接受了唐的答案,因为它解决了我的问题

我打开了电源

GeneralizedNewtypeDeriving 
增加

deriving (Eq, Ord, Num, Enum, Real, Integral)
对于我的每一个新类型,现在我可以使用标准fromIntegral对它们进行marshall处理


内森·豪厄尔的答案也是正确的,我投了更高的票。但不幸的是,他的解决方案意味着放弃像我现在使用的c2hs这样的FFI预处理器

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

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

例如:


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

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

例如:


GHC的FFI扩展允许使用包装FFI原语的新类型。您可以将导入的函数签名更改为使用新类型,并且(希望)避免手动打开它们

{-# 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
{-#语言外来函数接口#-}
模块主要在哪里
新类型Foo=Foo Int
国外进口ccall someCall::Foo->IO Foo
main::IO()
main=do
Foo x a->kc
解包=unK1。unM1。unM1。unM1。从…起
包装::(通用a,代表a~D1 dc(C1 cc(S1 sc(K1 R kc)))=>kc->a
打包。M1。M1。M1。K1
--C导入使用int
外部导入ccall“someCall”c'someCall::Int->IO Int
--并将键入的包装器打包/解包为FFI原语
someCall::Foo1->iofoo2
someCall=fmap包。来个电话。打开
main::IO()
main=do

GHC的FFI扩展允许使用包装FFI原语的新类型。您可以将导入的函数签名更改为使用新类型,并且(希望)避免手动打开它们

{-# 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
{-#语言外来函数接口#-}
模块主要在哪里
新类型Foo=Foo Int
国外进口ccall someCall::Foo->IO Foo
main::IO()
main=do
Foo x a->kc
解包=unK1。unM1。unM1。unM1。从…起
包装::(通用a,代表a~D1 dc(C1 cc(S1 sc(K1 R kc)))=>kc->a
打包。M1。M1。M1。K1
--C导入使用int
外部导入ccall“someCall”c'someCall::Int->IO Int
--并将键入的包装器打包/解包为FFI原语
someCall::Foo1->iofoo2
someCall=fmap包。来个电话。打开
main::IO()
main=do

Foo2 x谢谢,我会检查GeneraledNewTypeDeriving。我用的是c2hs。它要求我为任何非内置类型提供封送器。这就是我的问题。谢谢,我将检查GeneraledNewTypeDeriving。我用的是c2hs。它要求我为任何非内置类型提供封送器。因此我的问题是,我使用c2hs。它要求我为任何非内置类型提供封送器。有没有办法告诉c2hs在没有封送员的情况下按原样使用类型?@VagifVerdi我从未使用过c2hs,所以我不确定。看起来他们有一个newtype关键字,但它似乎与指针一起使用,而不是与原语一起使用。@VagifVerdi我也用另一个通用解决方案更新了我的答案。它也不需要Num/Integral实例,它们对于不透明指针类型来说似乎是不可取的。非常好的解决方案,谢谢。你的肯定更安全。我想知道那些吓人的包装会增加多少开销?另外,理想的做法是更改C2H以允许在不编组的情况下接受新类型。这样就不需要任何技巧了。@VagifVerdi生成的STG代码看起来非常相似(它们被编译掉了)。。。所以,毫不奇怪,根据标准衡量,它的性能几乎相同——在噪声范围内。我使用的是c2hs。它要求我为任何非内置类型提供封送器。有没有办法告诉c2hs在没有封送员的情况下按原样使用类型?@VagifVerdi我从未使用过c2hs,所以我不确定。看起来他们有一个newtype关键字,但它似乎与指针一起使用,而不是与原语一起使用。@VagifVerdi我也用另一个通用解决方案更新了我的答案。它也不需要Num/Integral实例,它们对于不透明指针类型来说似乎是不可取的。非常好的解决方案,谢谢。你的肯定更安全。我想知道那些吓人的包装会增加多少开销?另外,理想的做法是更改C2H以允许在不编组的情况下接受新类型。这样就不需要任何技巧了。@VagifVerdi生成的STG代码看起来非常相似(它们被编译掉了)。。。因此,毫不奇怪,根据标准衡量,它的性能几乎相同——在噪声范围内。