File: README.md

package info (click to toggle)
haskell-inline-c 0.9.1.10-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 260 kB
  • sloc: haskell: 3,059; makefile: 3
file content (322 lines) | stat: -rw-r--r-- 10,365 bytes parent folder | download | duplicates (2)
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