1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
|
# inline-c
`inline-c` lets you seamlessly call C libraries and embed
high-performance inline C code in Haskell modules. Haskell and C can
be freely intermixed in the same source file, and data passed to and
from code in either language with minimal overhead. No FFI required.
`inline-c` is Haskell's escape hatch (or one of) to the wild world of
legacy code and high-performance numerical and system libraries. It
has other uses too: you can also think of `inline-c` as to Haskell
what inline Assembly is to C — a convenient means to eke out a little
bit of extra performance in those rare cases where C still beats
Haskell.
GHCi support is currently limited to using `-fobject-code`, see
the [last section](#ghci) for more info.
## Getting started
Let's say we want to compute the cosine of a number using C from
Haskell. `inline-c` lets you write this function call inline, without
any need for a binding to the foreign function:
```
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
import qualified Language.C.Inline as C
C.include "<math.h>"
main :: IO ()
main = do
x <- [C.exp| double{ cos(1) } |]
print x
```
`inline-c` leverages the [quasiquotation][ghc-manual-quasiquotation]
language extension implemented in GHC.
[Template Haskell][ghc-manual-template-haskell] is also required.
Importing the `Language.C.Inline` module brings in scope most required
Haskell definitions. `C.include "<math.h>"` brings into scope the
foreign function `cos()` that we wish to call. Finally, in the `main`
function, `[C.exp| double { cos(1) } |]` denotes an inline C expression
of type `double`. `cexp` stands for "C expression". It is a custom
quasiquoter provided by `inline-c`.
A `C.exp` quasiquotation always includes a type annotation for the
inline C expression. This annotation determines the type of the
quasiquotation in Haskell. Out of the box, `inline-c` knows how to map
many common C types to Haskell types. In this case,
```
[C.exp| double { cos(1) } |] :: IO CDouble
```
For pure C expression like these we also provide `C.pure`, which works
exactly the same but without the `IO`:
```
[C.pure| double { cos(1) } |] :: CDouble
```
Obviously extra care must be taken when using `C.pure`: the embedded C
code must be referentially transparent.
## Multiple statements
`inline-c` allows embedding arbitrary C code, not just expressions, in
the form of a sequence of statements, using the `c` quasiquoter:
```
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
import qualified Language.C.Inline as C
C.include "<stdio.h>"
main :: IO ()
main = do
x <- [C.block| int {
// Read and sum 5 integers
int i, sum = 0, tmp;
for (i = 0; i < 5; i++) {
scanf("%d", &tmp);
sum += tmp;
}
return sum;
} |]
print x
```
Just as with `C.exp`, we need a type annotation on the entire C block.
The annotation specifies the return type. That is, the type of the
expression in any return statement.
## Capturing Haskell variables -- parameter declaration
`inline-c` allows referring to Haskell variables inside C expressions
and code blocks. We do so by "anti-quoting" them.
Let's say that we wanted to parameterize the function we wrote above
by how many numbers we should read. We can do so by defining a Haskell
function whose parameter we can refer to from within C:
```
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
import qualified Language.C.Inline as C
import Foreign.C.Types
C.include "<stdio.h>"
-- | @readAndSum n@ reads @n@ numbers from standard input and returns
-- their sum.
readAndSum :: CInt -> IO CInt
readAndSum n = [C.block| int {
// Read and sum n integers
int i, sum = 0, tmp;
for (i = 0; i < $(int n); i++) {
scanf("%d", &tmp);
sum += tmp;
}
return sum;
} |]
main :: IO ()
main = do
x <- readAndSum 5
print x
```
Here, the Haskell variable `n` is captured right where we need it using
`$(int n)`. Standard anti-quotation (we'll talk about additional ones
later) consists of a `$` followed by a C declaration in parenthesis.
Note that any valid Haskell identifiers can be used when anti-quoting,
including ones including constructors, qualified names, names containing
unicode, etc.
For each anti-quotation, a variable with a matching type is expected in
the Haskell environment. In this case `inline-c` expects a variable
named `n` of type `CInt`, which is the case.
## What can be captured and returned?
All C types correspond to exactly one Haskell type. Basic types (`int`,
`long`, `double`, `float`, etc.) get converted to their Haskell
equivalents `CInt`, `CLong`, `CDouble`, `CFloat`. Pointers and arrays
get converted to `Ptr`. Function pointers get converted to `FunPtr`.
`inline-c` can also handle user-defined structs and enums, provided that
they are instances of `Storable` and that you tell `inline-c` about them
using [contexts](#contexts).
## Contexts
Everything beyond the base functionality provided by `inline-c` is
specified in a structure that we call "`Context`". From a user
perspective, if we want to use anything but the default context
(`C.baseCtx`), we must set the `C.Context` explicitly using the
`C.context` function. The next two sections include several examples.
The `C.Context` allows to extend `inline-c` to support
* Custom C types beyond the basic ones;
* And [additional anti-quoters](#more-anti-quoters).
`C.Context`s can be composed using their `Monoid` instance.
Ideally a `C.Context` will be provided for each C library that should be
used with `inline-c`. The user can then combine multiple contexts
together if multiple libraries are to be used in the same program. See
the [`inline-c-nag` package](https://github.com/fpco/inline-c-nag) for
an example of using a `C.Context` tailored for a library.
For information regarding how to define `C.Context`s, see the
Haddock-generated API documentation for `Language.C.Inline.Context`.
## More anti-quoters
Besides the basic anti-quoter, which captures variables as they are,
some more anti-quoters are provided with additional functionality. As
mentioned, `inline-c` can easily be extended with anti-quoters defined
by the user, using [contexts](#contexts).
### Vectors
The `vec-len` and `vec-ptr` anti-quoters in the `C.vecCtx` context let us
easily use [Haskell vectors](http://hackage.haskell.org/package/vector)
in C. Continuing along the "summing" theme, we can write code that sums
Haskell vectors in C:
```
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
import qualified Language.C.Inline as C
import qualified Data.Vector.Storable as V
import qualified Data.Vector.Storable.Mutable as VM
import Data.Monoid ((<>))
import Foreign.C.Types
-- To use the vector anti-quoters, we need the 'C.vecCtx' along with the
-- 'C.baseCtx'.
C.context (C.baseCtx <> C.vecCtx)
sumVec :: VM.IOVector CDouble -> IO CDouble
sumVec vec = [C.block| double {
double sum = 0;
int i;
for (i = 0; i < $vec-len:vec; i++) {
sum += $vec-ptr:(double *vec)[i];
}
return sum;
} |]
main :: IO ()
main = do
x <- sumVec =<< V.thaw (V.fromList [1,2,3])
print x
```
The `vec-len` anti-quoter is used simply by specifying the vector we
want to get the length of (in our case, `vec`). To use the `vec-ptr`
anti-quoter it is also required to specify the pointer type we want.
Since `vec` is a vector of `CDouble`s, we want a pointer to `double`s.
## ByteStrings
The `bs-len` and `bs-ptr` anti-quoters in the `C.bsCtx` context work
exactly the same as the `vec-len` and `vec-ptr` counterparts, but with
strict `ByteString`s. The only difference is that it is not necessary to
specify the type of the pointer from C -- it is always going to be
`char *`:
```
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
import qualified Data.ByteString as BS
import Data.Monoid ((<>))
import Foreign.C.Types
import qualified Language.C.Inline as C
C.context (C.baseCtx <> C.bsCtx)
-- | Count the number of set bits in a 'BS.ByteString'.
countSetBits :: BS.ByteString -> IO CInt
countSetBits bs = [C.block|
int {
int i, bits = 0;
for (i = 0; i < $bs-len:bs; i++) {
char ch = $bs-ptr:bs[i];
bits += (ch * 01001001001ULL & 042104210421ULL) % 017;
}
return bits;
}
|]
```
### Function pointers
Using the `fun` anti-quoter, present in the `C.funCtx` context, we can
easily turn Haskell function into function pointers.
```
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
import qualified Language.C.Inline as C
-- To use the function pointer anti-quoter, we need the 'C.funCtx' along with
-- the 'C.baseCtx'.
C.context (C.baseCtx <> C.funCtx)
ackermann :: CLong -> CLong -> CLong
ackermann m n
| m == 0 = n + 1
| m > 0 && n == 0 = ackermann (m - 1) 1
| otherwise = ackermann (m - 1) (ackermann m (n - 1))
main :: IO ()
main = do
let ackermannIO m n = return $ ackermann m n
let x = 3
let y = 4
z <- [C.exp| long{
$fun:(long (*ackermannIO)(long, long))($(long x), $(long y))
} |]
print z
```
In this example, we capture a Haskell function of type `CLong -> CLong
-> IO CLong`, `ackermannIO`, to a function pointer in C, using the `fun`
anti-quoter. Note how we need to specify the function pointer type when
we capture `ackermannIO`, using standard C declaration syntax. Also
note that the `fun` anti-quoter works with `IO` functions, and so we
needed to modify `ackermann` to make it have the right type.
In general, when anti-quoting, if the type can be inferred (like in the
case of `vec-len`), only the Haskell identifier appears. If it can't,
the target C type and the Haskell identifier are mentioned using C
declaration syntax.
## GHCi
Currently `inline-c` does not work in interpreted mode. However, GHCi
can still be used using the `-fobject-code` flag. For speed, we
recommend passing `-fobject-code -O0`, for example
```
stack ghci --ghci-options='-fobject-code -O0'
```
or
```
cabal repl --ghc-options='-fobject-code -O0'
```
[ghc-manual-quasiquotation]:
https://downloads.haskell.org/ghc/latest/docs/html/users_guide/glasgow_exts.html#template-haskell-quasi-quotation
[ghc-manual-template-haskell]:
https://downloads.haskell.org/ghc/latest/docs/html/users_guide/glasgow_exts.html#template-haskell
|