内联-c
内联-c
可以无缝调用C库并嵌入Haskell模块中的高性能内联C代码。哈斯克尔和C罐在同一源文件中自由混合,数据传递到和以最小的开销从任何一种语言的代码中获取。无需外国金融机构。
内联-c
哈斯克尔的逃生舱口(或其中之一)是遗留代码和高性能数值和系统库。它还有其他用途:你也可以想到内联-c
至于哈斯克尔内联汇编对C来说是什么?这是一种方便的方法,可以稍微弥补一下在C仍然优于C的罕见情况下有点额外的性能哈斯克尔。
GHCi支持目前仅限于使用-fobject-code(对象代码)
,请参阅这个最后一节了解更多信息。
入门
假设我们想用C计算一个数字的余弦哈斯克尔。内联-c
允许您内联编写此函数调用,而无需需要绑定到外部函数:
{-#LANGUAGE准引号#-}{-#LANGUAGE模板Haskell#-}导入限定语言。C.内联为CC.include“<math.h>”主::IO()main=做x<-[C.exp|double{cos(1)}|]打印x
内联-c
利用准报价GHC中实现的语言扩展。模板Haskell也是必需的。导入语言。C.内联
模块引入了最需要的范围Haskell定义。C.include“<math.h>”
将外国职能cos()
我们想打电话给他。最后,在主要的
功能,[C.exp|double{cos(1)}|]
表示内联C表达式类型为双重的
.欧洲化学工程师协会
代表“C表达式”。这是一种习惯准引用由提供内联-c
.
A类C.exp公司
准引号始终包含内联C表达式。此注释确定Haskell中的准引用。开箱即用,内联-c
知道如何绘制地图从许多常见的C类型到Haskell类型。在这种情况下,
[C.exp|double{cos(1)}|]::IO双精度
对于像这样的纯C表达式,我们还提供C.纯
,有效完全相同,但没有IO(输入输出)
:
[C.pure |双{cos(1)}|]::C双
显然,使用时必须格外小心C.纯
:嵌入式C代码必须是引用透明的。
多个语句
内联-c
允许在中嵌入任意C代码,而不仅仅是表达式语句序列的形式,使用c(c)
准引用:
{-#LANGUAGE准引号#-}{-#LANGUAGE模板Haskell#-}导入限定语言。C.内联为CC.include“<stdio.h>”主::IO()main=做x<-[C.块|int{//读取5个整数并求和整数i,总和=0,tmp;对于(i=0;i<5;i++){scanf(“%d”,/tmp);总和+=tmp;}收益总额;} |]打印x
正如C.exp公司
,我们需要对整个C块进行类型注释。注释指定返回类型。也就是说任何返回语句中的表达式。
捕获Haskell变量--参数声明
内联-c
允许在C表达式中引用Haskell变量和代码块。我们通过“反引用”来做到这一点。
假设我们想参数化上面编写的函数我们应该读多少数字。我们可以通过定义Haskell来实现我们可以从C中引用其参数的函数:
{-#LANGUAGE准引号#-}{-#LANGUAGE模板Haskell#-}导入限定语言。C.内联为C进口国外产品。C.类型C.包括“<stdio.h>”--|@readAndSum n@从标准输入中读取@n@数字并返回--他们的总和。读取和总和::CInt->IO CIntreadAndSum n=[C.block|int{//读取n个整数并求和整数i,总和=0,tmp;对于(i=0;i<$(int n));i++){扫描(“%d”,&tmp);总和+=tmp;}收益总额;}|]主::IO()main=做x<-读取和求和5打印x
这里是Haskell变量n个
就在我们需要的地方使用$(整数n)
.标准反报价(我们将讨论附加报价稍后)由$
后面是括号中的C声明。注意,在反引号时可以使用任何有效的Haskell标识符,包括构造函数、限定名、包含unicode等。
对于每个反引号,在Haskell环境。在这种情况下内联-c
需要一个变量命名n个
类型为CInt公司
,情况就是这样。
可以捕获和返回什么?
所有C类型只对应一个Haskell类型。基本类型(整数
,长的
,双重的
,浮动
等)转换为他们的Haskell等价物CInt公司
,CLong公司
,C双倍
,C浮标
.指针和数组转换为Ptr公司
。函数指针被转换为FunPtr(功能点)
.
内联-c
也可以处理用户定义的结构和枚举,前提是它们是可存储
你告诉我的内联-c
关于他们使用上下文.
上下文
提供的基本功能之外的一切内联-c
是在我们称之为“上下文
“。来自用户透视图,如果我们想使用默认上下文以外的任何内容(C.baseCtx公司
),我们必须设置C.背景
显式使用C.上下文
功能。接下来的两部分包括几个示例。
这个C.背景
允许扩展内联-c
以支持
C.背景
s可以使用它们的单体
例如。
理想情况下C.背景
将为每个应该与一起使用内联-c
。然后用户可以组合多个上下文如果要在同一程序中使用多个库,请将它们放在一起。请参见这个内联-c-nag
包裹对于使用C.背景
为图书馆量身定制。
有关如何定义的信息C.背景
s、 请参阅Haddock生成的API文档语言。C.内联。上下文
.
更多反引用
除了基本的anti-quoter,它可以捕获当前的变量,一些更多的反引用提供了额外的功能。作为如前所述,内联-c
可以通过定义反引用轻松扩展由用户使用上下文.
矢量
这个vec-len公司
和vec-ptr
反引用C.vecCtx公司
上下文让我们易于使用哈斯克尔矢量继续“求和”主题,我们可以编写求和的代码C中的Haskell向量:
{-#LANGUAGE准引号#-}{-#LANGUAGE模板Haskell#-}导入限定语言。C.内联为C导入合格数据。矢量。可存储为V导入合格数据。矢量。可储存。可变为VM导入数据。单体((<>))进口国外产品。C.类型--要使用矢量反引用,我们需要“C.vecCtx”和--“C.baseCtx”。上下文(C.baseCtx<>C.vecCtx)sumVec::虚拟机。IOVector CDouble->IO CDoublesumVec-vec=[C.block|double{双和=0;整数i;对于(i=0;i<$vec-len:vec;i++){总和+=$vec-ptr:(双*vec)[i];}收益总额;} |]主::IO()main=做x<-sumVec=<<V.sawe(V.fromList[1,2,3])打印x
这个向量长度
anti-quoter只需指定向量we想要得到的长度(在我们的例子中,血管内皮细胞
). 要使用vec-ptr
anti-quoter还需要指定所需的指针类型。自血管内皮细胞
是的向量C双倍
s、 我们想要一个指向双重的
第条。
字节字符串
这个bs-len(英国标准)
和bs-ptr型
反引用C.bsCtx公司
上下文工作与vec-len公司
和vec-ptr
副本,但具有严格的字节字符串
s.唯一的区别是没有必要指定C中指针的类型--它总是字符*
:
{-#LANGUAGE模板Haskell#-}{-#语言四引号#-}导入合格数据。字节字符串作为BS导入数据。单体((<>))进口国外产品。C.类型导入限定语言。C.内联为C上下文(C.baseCtx<>C.bsCtx)--|统计“BS.ByteString”中的设置位数。countSetBits::BS.ByteString->IO CIntcountSetBits bs=[C.块|整数{int i,位=0;for(i=0;i<$bs len:bs;i++){char ch=$bs-ptr:bs[i];位+=(ch*01001001001ULL&042104210421ULL)%017;}返回位;}|]
函数指针
使用乐趣
anti-quoter,存在于C.funCtx公司
上下文,我们可以轻松地将Haskell函数转换为函数指针。
{-#LANGUAGE准引号#-}{-#LANGUAGE模板Haskell#-}导入限定语言。C.内联为C--要使用函数指针anti-quoter,我们需要“C.funCtx”以及--“C.baseCtx”。上下文(C.baseCtx<>C.funCtx)阿克曼::CLong->CLong->CLong阿克曼|m==0=n+1|m>0&&n==0=ackermann(m-1)1|否则=阿克曼(m-1)(阿克曼m(n-1))主::IO()main=做让ackermannIO m n=返回$ackermann m n设x=3设y=4z<-[C.exp|long{$fun:(long(*ackermannIO)(long,long))($(long x),$(long y))} |]打印z
在这个示例中,我们捕获了一个类型为CLong->CLong->IO CLong
,阿克曼IO
,指向C中的函数指针,使用乐趣
反引用。请注意,当我们捕获阿克曼IO
,使用标准的C声明语法。阿尔索注意乐趣
anti-quoter与IO(输入输出)
函数,所以我们需要修改阿克曼
使其具有正确的类型。
通常,在反引号时,如果可以推断类型(如案例vec-len公司
),只显示Haskell标识符。如果不能,目标C类型和Haskell标识符使用C声明语法。
解释方式
目前内联-c
无法在解释模式下工作。然而,GHCi仍然可以使用-fobject-code(对象代码)
标志。为了速度,我们推荐通过-对象代码-O0
例如
堆栈ghci--ghci-options='-fobject-code-O0'
或
cabal repl--ghc-options='-fobject-code-O0'