haskell - CPP : Macros in Haskell

标签 haskell ffi

我正在使用 bindings-DSL 来帮助处理 FFI 声明中的一些样板文件。但是我发现自己声明了一组仅相差几个文本元素的相关函数,我真的更愿意用宏来声明这些函数。 CPP 或 CPPHS 似乎是理想的选择,但我找不到在 Haskell 上下文中使用它的任何示例。

根据我对 C 宏的了解,我已将其放入我大约期望的工作中:

#define declare_vector_funcs (t, tn, ct) \ 
    #opaque_t vector_##t \
    #ccall create_std_vector##tn , IO (Ptr <vector_##t##>) \
    #ccall carray_to_std_vector##tn , Ptr ct -> CSize -> IO (Ptr <vector_##t##>) \
    #ccall std_vector##tn##_to_carray , Ptr <vector_##t##> -> IO (Ptr ct) \
    #ccall std_vector##tn##_length , Ptr <vector_##t##> -> IO CSize

本质上,我想在扩展这个宏时定义一个外部(不透明)类型和 4 个外部函数。但是,这不起作用,因为它将参数列表后面的所有内容都读取为 GHC pragma,并且失败了。

我已经尝试了几个不同的迭代,例如弄乱间距并将所有内容放在一行中(用括号括起来以区分单独的宏调用)。

我该如何解决这个问题?放弃绑定(bind)-DSL 使用以支持直接翻译的答案很好,但我绝对不想手工写出所有这些。

我也非常感谢这种 CPP 用法的一些例子。

如果我删除宏名称和参数列表之间的空格,这是我收到的错误消息:
CPP.hsc:13:39: error: '#' is not followed by a macro parameter
compiling dist/build/Foreign/CPP_hsc_make.c failed (exit code 1)
command was: /usr/bin/g++ -c dist/build/Foreign/CPP_hsc_make.c -o dist/build/Foreign/CPP_hsc_make.o -fno-stack-protector -D__GLASGOW_HASKELL__=708 -Dlinux_BUILD_OS=1 -Dx86_64_BUILD_ARCH=1 -Dlinux_HOST_OS=1 -Dx86_64_HOST_ARCH=1 -Iinclude/ -fpermissive -std=c++11 -fPIC -Idist/build/autogen -include dist/build/autogen/cabal_macros.h -I/usr/local/lib/x86_64-linux-ghc-7.8.2/bindings-DSL-1.0.21/include -I/usr/lib/ghc-7.8.2/base-4.7.0.0/include -I/usr/lib/ghc-7.8.2/integer-gmp-0.5.1.0/include -I/usr/lib/ghc-7.8.2/include -I/usr/lib/ghc-7.8.2/include/

有了这个空间,我会收到一条更长的错误消息:
dist/build/Foreign/CPP.hs:1:16:
    unknown flag in  {-# OPTIONS_GHC #-} pragma: tn,
dist/build/Foreign/CPP.hs:1:16:
    unknown flag in  {-# OPTIONS_GHC #-} pragma: ct)
dist/build/Foreign/CPP.hs:1:16:
    unknown flag in  {-# OPTIONS_GHC #-} pragma: #opaque_t
dist/build/Foreign/CPP.hs:1:16:
    unknown flag in  {-# OPTIONS_GHC #-} pragma: vector_##t

对于每个 token ,这种情况都会继续。我相当肯定这只是意味着不应包含该空间,但我不确定发生了什么。

编辑:

新信息。

我交换了方法,并试图直接生成最终的外国进口。宏(我将稍后粘贴)通过预处理器并发出几个警告,但实际上尝试使用宏还不起作用:
#define declare_vector_funcs(t, tn ,ct) \
    data C'vector_##t = C'vector_##t \
    foreign import ccall "create_std_vector##tn" c'create_std_vector##tn :: IO (Ptr C'vector_##t) \
    foreign import ccall "carray_to_std_vector##tn" c'carray_to_std_vector##tn :: Ptr ct -> CSize -> IO (Ptr vector_##t) \
    foreign import ccall "std_vector##tn##_to_carray" c'std_vector##tn##_to_carray :: Ptr vector_##t -> IO (Ptr ct) \
    foreign import ccall "std_vector##tn##_length" c'std_vector :: Ptr vector_##t -> IO CSize

在使用站点上,我尝试像这样使用它:
#declare_vector_funcs int , i , CInt

匹配 C 端的等效声明。我希望它生成一个如下所示的 block :
data C'vector_int = C'vector_int 
foreign import ccall "create_std_vectori" c'create_std_vectori :: IO (Ptr C'vector_int) 
foreign import ccall "carray_to_std_vectori" c'carray_to_std_vectori :: Ptr CInt -> CSize -> IO (Ptr vector_int) 
foreign import ccall "std_vectori_to_carray" c'std_vectori_to_carray :: Ptr vector_int -> IO (Ptr CInt) 
foreign import ccall "std_vectori_length" c'std_vector :: Ptr vector_int -> IO CSize

但相反,我得到一个错误:
CPP.hsc: In function ‘int main(int, char**)’:
CPP.hsc:22:31: error: expected primary-expression before ‘int’
CPP.hsc:22:37: error: ‘i’ was not declared in this scope
CPP.hsc:22:41: error: ‘CInt’ was not declared in this scope
CPP.hsc:22:45: error: ‘hsc_declare_vector_funcs’ was not declared in this scope
CPP.hsc:23:31: error: expected primary-expression before ‘float’
CPP.hsc:23:39: error: ‘f’ was not declared in this scope
CPP.hsc:23:43: error: ‘CFloat’ was not declared in this scope
CPP.hsc:24:31: error: expected primary-expression before ‘double’
CPP.hsc:24:40: error: ‘d’ was not declared in this scope
CPP.hsc:24:44: error: ‘CDouble’ was not declared in this scope

所以我显然需要添加import Foreign.C到顶部,但即便如此,还有一个更深层次的问题——我不能像我想的那样把这些标记视为毫无意义,有些东西正试图真正解释它们。有人有想法么?

最佳答案

当您在 hsc 中定义宏时,我认为您尝试做的事情不太可能。文件将内联到您生成的 .hs文件,如果该宏调用 .hsc宏..那些将不再可用。你能做到的最好的:

module Test where

import Foreign.Ptr
import Foreign.C.Types

data T
data Tn
data Ct

#opaque_t vector_T
#ccall create_std_vectorTn , IO (Ptr <vector_T>)
#ccall carray_to_std_vectorTn , Ptr Ct -> CSize -> IO (Ptr <vector_T>) 
#ccall std_vectorTn_to_carray , Ptr <vector_T> -> IO (Ptr Ct) 
#ccall std_vectorTn_length , Ptr <vector_T> -> IO CSize

如果您的 C 编译器知道在哪里可以找到 bindings.dsl.h那么你应该把它放在顶部;我的不是,所以我用 hsc2hs --include=<path-to-bindings.dsl.h> test.hsc 编译.这会产生以下文件:
{-# LINE 1 "test.hsc" #-}
module Test where
{-# LINE 2 "test.hsc" #-}

import Foreign.Ptr
import Foreign.C.Types

data T
data Tn
data Ct

data C'vector_T = C'vector_T

{-# LINE 11 "test.hsc" #-}
foreign import ccall "create_std_vectorTn" c'create_std_vectorTn
  :: IO (Ptr C'vector_T)
foreign import ccall "&create_std_vectorTn" p'create_std_vectorTn
  :: FunPtr (IO (Ptr C'vector_T))

{-# LINE 12 "test.hsc" #-}
foreign import ccall "carray_to_std_vectorTn" c'carray_to_std_vectorTn
  :: Ptr Ct -> CSize -> IO (Ptr C'vector_T)
foreign import ccall "&carray_to_std_vectorTn" p'carray_to_std_vectorTn
  :: FunPtr (Ptr Ct -> CSize -> IO (Ptr C'vector_T))

{-# LINE 13 "test.hsc" #-}
foreign import ccall "std_vectorTn_to_carray" c'std_vectorTn_to_carray
  :: Ptr C'vector_T -> IO (Ptr Ct)
foreign import ccall "&std_vectorTn_to_carray" p'std_vectorTn_to_carray
  :: FunPtr (Ptr C'vector_T -> IO (Ptr Ct))

{-# LINE 14 "test.hsc" #-}
foreign import ccall "std_vectorTn_length" c'std_vectorTn_length
  :: Ptr C'vector_T -> IO CSize
foreign import ccall "&std_vectorTn_length" p'std_vectorTn_length
  :: FunPtr (Ptr C'vector_T -> IO CSize)

{-# LINE 15 "test.hsc" #-}

所以看起来定义自己的宏是要走的路:

我的宏
#define hsc_declare_vector_funcs(t,tn,ct)\
  hsc_opaque_t(vector_##t)\
  hsc_ccall(create_std_vector##tn ,IO (Ptr <vector_##t>))\
  hsc_ccall(carray_to_std_vector##tn , Ptr ct -> CSize -> IO (Ptr <vector_##t>)) \
  hsc_ccall(std_vector##tn##_to_carray , Ptr <vector_##t> -> IO (Ptr ct)) \
  hsc_ccall(std_vector##tn##_length , Ptr <vector_##t> -> IO CSize)

测试.hsc
module Test where

#include "mymacro.h"

import Foreign.Ptr
import Foreign.C.Types

#declare_vector_funcs int, i, CInt

测试.hs
module Test where

import Foreign.Ptr
import Foreign.C.Types

data C'vector_int = C'vector_int
foreign import ccall "create_std_vectori" c'create_std_vectori
  :: IO (Ptr C'vector_int)
foreign import ccall "&create_std_vectori" p'create_std_vectori
  :: FunPtr (IO (Ptr C'vector_int))
foreign import ccall "carray_to_std_vectori" c'carray_to_std_vectori
  :: Ptr CInt -> CSize -> IO (Ptr C'vector_int)
foreign import ccall "&carray_to_std_vectori" p'carray_to_std_vectori
  :: FunPtr (Ptr CInt -> CSize -> IO (Ptr C'vector_int))
foreign import ccall "std_vectori_to_carray" c'std_vectori_to_carray
  :: Ptr C'vector_int -> IO (Ptr CInt)
foreign import ccall "&std_vectori_to_carray" p'std_vectori_to_carray
  :: FunPtr (Ptr C'vector_int -> IO (Ptr CInt))
foreign import ccall "std_vectori_length" c'std_vectori_length
  :: Ptr C'vector_int -> IO CSize
foreign import ccall "&std_vectori_length" p'std_vectori_length
  :: FunPtr (Ptr C'vector_int -> IO CSize)

关于haskell - CPP : Macros in Haskell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23256108/

相关文章:

haskell - 在 Haskell 中,如何区分一元函数定义中的可变引用与常规变量

haskell - 如何使用 Haskell pretty-print 分层缩进 "nest"

.net - 你如何在 Mono 中使用 ALSA?

c - haskell FFI传入和传出C结构数组

windows - 如何让 text-icu 在 Windows 上运行?

haskell - "overloading"能否通过 FlexibleInstances 返回不同的类型,或者匹配类型类?

haskell - 开始使用 Haskell

haskell - 使用 Haskell FFI 来编码(marshal)结构;另外,如何使用 FunPtr

windows - 获取固定驱动器列表

c - 为什么从 C 调用 Haskell 函数会有开销?