CPP – Haskell – Aelve Guidehttps://guide.aelve.com/haskell/feed/category/vww0qd722017-05-13T21:26:26Zo88ct0bbbase-feature-macros2017-05-13T21:26:26Z<h1> <span class="item-name">base-feature-macros</span>
(<a href="https://hackage.haskell.org/package/base-feature-macros">Hackage</a>)
</h1><p>The <a href="https://hackage.haskell.org/package/base-feature-macros">base-feature-macros</a> package lets you write some macros more conveniently – e.g. instead of <code>#if MIN_VERSION_base(4,8,0)</code> you can write <code>#if HAVE_FOLDABLE_TRAVERSABLE_IN_PRELUDE</code>, which is much more understandable to a casual reader.</p>
v27x182dDifferences between GCC and Clang2017-02-13T21:26:53Z<h1> <span class="item-name">Differences between GCC and Clang</span>
</h1><p>On Linux and Windows, GCC's CPP is used for preprocessing; on macOS – Clang's CPP. They have some differences, which you have to account for (unless you're using cpphs).</p>
<p>If you're on Linux, use <code>ghc -pgmP "clang -E -undef -traditional" file.hs</code> to check whether your code would compile with Clang. If you use CI (e.g. Travis-CI), you can add it to your .cabal file in the <code>ghc-options</code> section (hidden under a flag) and run your CI builds both with and without the flag.</p>
<hr />
<h1>Single quotes</h1>
<p>Clang is more strict about single quotes than GCC. For instance, this piece of code using <code>-XDataKinds</code> won't be expanded correctly by Clang:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#define X(a) Foo '[a]</span>
X(Int) <- expanded into “Foo '[a]”</code></pre></div>
<p>A workaround is defining a separate macro for <code>'</code>:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#define QUOTE '</span>
<span class="pp">#define X(a) Foo QUOTE[a]</span>
X(Int) <- expanded into “Foo '[Int]”</code></pre></div>
<p>If you need to surround something with single quotes, this might help:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#define QUOTE() '</span>
<span class="pp">#define QLEFT(a) QUOTE()a</span>
<span class="pp">#define Q(a) QLEFT(a)'</span>
Q(Int) <- expanded into “'Int'”</code></pre></div>
<h1>Concatenation</h1>
<p>GCC expands the following macro as <code>_foo</code>, but Clang adds a space and produces <code>_ foo</code>:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#define U(x) _</span><span class="co">/**/</span><span class="pp">x</span>
U(foo)</code></pre></div>
<p>There is no way to get rid of the space on Clang. Either rewrite your code to not need such tricks, or use cpphs.</p>
uqlwbvrwUse cpphs as the preprocessor2017-02-11T21:48:30Z<h1> <span class="item-name">Use cpphs as the preprocessor</span>
</h1><p>Sometimes it's easier to use <a href="http://projects.haskell.org/cpphs/">cpphs</a> than to fight with GCC's and Clang's differences, idiosyncrasies, etc:</p>
<blockquote>
<p>[...] There have always been problems with, for instance, string gaps, and prime characters in identifiers. These problems are only going to get worse.</p>
<p>So, it seemed right to provide an alternative to cpp, both more compatible with Haskell, and itself written in Haskell so that it can be distributed with compilers.</p>
</blockquote>
<p>Cpphs handles single quotes and <code>/**/</code> correctly, doesn't mangle Haddock comments and knows about Haskell's multiline strings.</p>
<p>To use cpphs, you need to add these options to all sections of your .cabal file:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode">library
...
build-tools: cpphs >= 1.19
ghc-options: -pgmP cpphs -optP --cpp</code></pre></div>
<p>A warning: Stack will install cpphs automatically, but cabal-install might not (and then you'd have to install it manually). Thus, depending on cpphs isn't recommended for libraries that would be published on Hackage.</p>
<p>If you can't use cpphs because of its modified LGPL license (e.g. in corporate environment where each license has to be vetted by a lawyer), you can use <a href="https://github.com/acowley/hpp">hpp</a> instead.</p>
nrzc15chDefine a macro2017-02-09T11:30:14Z<h1> <span class="item-name">Define a macro</span>
</h1><p>Macros are useful when you need to write repetitive code but don't want to use Template Haskell (either because it's hard or because you want to avoid the compilation time penalty). For example,
<a href="https://hackage.haskell.org/package/monad-control">monad-control</a> uses macros to <a href="https://github.com/basvandijk/monad-control/blob/4a3ec0631dda597b1b13d1a6a756d3b651f511b4/Control/Monad/Trans/Control.hs#L332-L354">generate instances</a>, and
GHC uses macros to <a href="https://github.com/ghc/ghc/blob/b9bebd8cedccd7e8dd6df89b5504cd8f1e7a675b/libraries/base/GHC/Float/RealFracMethods.hs#L62-L76">define shorter function names</a>.</p>
<p>The simplest example is defining a synonym for a function:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#define FI fromIntegral</span></code></pre></div>
<p>Now <code>FI</code> can be used anywhere instead of <code>fromIntegral</code>. As mentioned in the introduction, it won't be expanded inside strings or words; still, it might be better to undefine it after use:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#undef FI</span></code></pre></div>
<p>We can define a more complex macro with parameters. For instance, instead of generating lenses with <code>makeLenses</code> we could do it with macros (sometimes it's a necessary evil, like when you want to define lenses for data families):</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#define MAKE_LENS(field, lens) lens f s = (\y -> s {field = y}) <$> f (field s)</span>
-- | Lens <span class="cf">for</span> foo.
foo :: Lens' (SomeFamily Int) Foo
MAKE_LENS(foo, _foo)</code></pre></div>
<p>(Note that we can't get rid of repetition – <code>foo</code>, <code>_foo</code> – without breaking compatibility with Clang. If you <a href="#item-uqlwbvrw">use cpphs</a> or don't need your code to compile on macOS, you can use <code>/**/</code> to add the underscore instead.)</p>
<p>Finally, you can use <code>\</code> for longer macros:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#define BASE(M) \</span>
<span class="pp">instance MonadBaseControl (M) (M) where { \</span>
<span class="pp"> type StM (M) a = a; \</span>
<span class="pp"> liftBaseWith f = f id; \</span>
<span class="pp"> restoreM = return; \</span>
<span class="pp"> {-# INLINABLE liftBaseWith #-}; \</span>
<span class="pp">{-# INLINABLE restoreM #-}}</span></code></pre></div>
<p>This macro isn't actually multiline, though – it will be expanded into a single line (which is why curly braces were used and there's <code>;</code> after every line).</p>
oh9ytz0pDefine a .cabal flag2017-02-07T18:12:40Z<h1> <span class="item-name">Define a .cabal flag</span>
</h1><p>Let's say you want to add asserts to your code. First, add a flag to your <code>.cabal</code> file:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode">Flag asserts
Description: Turn on asserts
Default: False
library
exposed-modules: ...
if flag(asserts)
cpp-options: -DASSERTS</code></pre></div>
<p>(It's also possible to define a constant by writing <code>-DFOO=bar</code>.)</p>
<p>Now, to enable a flag during compilation, do this (to disable, use <code>-asserts</code> instead of <code>asserts</code>):</p>
<ul>
<li>Cabal: <code>cabal configure -f asserts</code></li>
<li>Stack: <code>stack build --flag pkgname:asserts</code></li>
</ul>
<p>Then you can check for this flag in code:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#ifdef ASSERTS</span>
...
<span class="pp">#endif</span></code></pre></div>
v8clrp5xDetect Int/Word size2017-02-05T15:20:04Z<h1> <span class="item-name">Detect Int/Word size</span>
</h1><p>You can use CPP to find out whether <code>Int</code> and <code>Word</code> have 32 bits, 64 bits, or (if you're unlucky) some other amount of bits. First you'll have to add <code>#include "MachDeps.h"</code> to the beginning of the file. This makes the <code>WORD_SIZE_IN_BITS</code> variable available:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#if (WORD_SIZE_IN_BITS == 64)</span>
...
<span class="pp">#else</span>
...
<span class="pp">#endif</span></code></pre></div>
<p>There are <a href="https://github.com/ghc/ghc/blob/master/includes/MachDeps.h">other constants</a> defined in MachDeps.h as well.</p>
flz6li4lDetect architecture2017-02-05T15:00:07Z<h1> <span class="item-name">Detect architecture</span>
</h1><p>There are variables for detecting architecture:</p>
<ul>
<li><strong><code>i386_HOST_ARCH</code> – x86</strong></li>
<li><strong><code>x86_64_HOST_ARCH</code> – x64</strong></li>
<li><code>arm_HOST_ARCH</code> – ARM (there's also <code>arm_HOST_ARCH_PRE_ARMv7</code>)</li>
<li><code>powerpc_HOST_ARCH</code></li>
<li><code>sparc_HOST_ARCH</code></li>
</ul>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#if defined(i386_HOST_ARCH)</span>
...
<span class="pp">#elif defined(x86_64_HOST_ARCH)</span>
...
<span class="pp">#else</span>
<span class="pp"># error Unsupported architecture</span>
<span class="pp">#endif</span></code></pre></div>
<p><code># error Unsupported architecture</code> will emit an error at the CPP step (and stop compilation) if the architecture isn't one of the above.</p>
qbrikka7Detect OS2017-02-05T14:39:07Z<h1> <span class="item-name">Detect OS</span>
</h1><p>The following variables are defined depending on OS:</p>
<ul>
<li><strong><code>mingw32_HOST_OS</code> – Windows</strong></li>
<li><strong><code>darwin_HOST_OS</code> – macOS</strong></li>
<li><code>ghcjs_HOST_OS</code> – Javascript (when compiling with GHCJS)</li>
<li><code>linux_HOST_OS</code> – Linux (shouldn't be needed most of the time)</li>
<li><code>freebsd_HOST_OS</code> – FreeBSD</li>
<li><code>netbsd_HOST_OS</code> – NetBSD</li>
<li><code>openbsd_HOST_OS</code> – OpenBSD</li>
<li><code>solaris_HOST_OS</code> – Solaris</li>
</ul>
<p>For instance, here's how you can detect macOS:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#ifdef darwin_HOST_OS</span>
...
<span class="pp">#endif</span></code></pre></div>
<p>Note that despite lots of libraries using <code>#if defined(mingw32_HOST_OS) || defined(__MINGW32__)</code> for detecting Windows, you don't need to do it – just <code>mingw32_HOST_OS</code> will suffice. See this <a href="https://ghc.haskell.org/trac/ghc/ticket/9945#comment:15">Trac ticket</a>.</p>
c84cb8q3Detect Hlint2017-02-05T14:31:16Z<h1> <span class="item-name">Detect Hlint</span>
</h1><p>Sometimes you want to hide some code from <a href="https://github.com/ndmitchell/hlint">Hlint</a> (for instance, if Hlint's parser doesn't support a particular language feature yet).</p>
<p>You can do it by defining <code>HLINT</code> (e.g. by writing a script like <a href="https://github.com/ekmett/lens/blob/6f8e5539fccca2e07a3e0b54bb0ec3364f9f3d52/tests/hlint.hs">lens</a> does, or just by passing <code>--cpp-define=HLINT</code> to Hlint) and then wrapping code into an <code>#ifndef HLINT</code> section:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#ifndef HLINT</span>
...
<span class="pp">#endif</span></code></pre></div>
qxhl6vk6Check version of a library2017-02-05T14:16:36Z<h1> <span class="item-name">Check version of a library</span>
</h1><p>Cabal automatically generates macros (<code>MIN_VERSION_<library></code>) for all libraries your project depends upon. E.g. you can do something if e.g. <code>bytestring</code> is 0.10.4 or newer:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#if MIN_VERSION_bytestring(0,10,4)</span>
...
<span class="pp">#endif</span></code></pre></div>
<p>If a library has hyphens <code>-</code> in its name, replace them with underscores <code>_</code>:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#if MIN_VERSION_template_haskell(2,11,0)</span>
...
<span class="pp">#endif</span></code></pre></div>
fkuvztqeCheck GHC version2017-02-04T14:35:56Z<h1> <span class="item-name">Check GHC version</span>
</h1><p><em>GHC versions currently in use: 7.8 = <code>708</code>, 7.10 = <code>710</code>, 8.0 = <code>800</code>.</em></p>
<p>Do something if GHC is older than 7.10:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#if __GLASGOW_HASKELL__ < 710</span>
...
<span class="pp">#endif</span></code></pre></div>
<p>Use different code for GHC 8.0 and older versions:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="pp">#if __GLASGOW_HASKELL__ >= 800</span>
...
<span class="pp">#else</span>
...
<span class="pp">#endif</span></code></pre></div>
<p>If you need to check for patch level as well (e.g. detect GHC 8.0.1 but not 8.0.2), you can use a .cabal flag:</p>
<div class="sourceCode"><pre class="sourceCode"><code class="sourceCode">library
...
if impl(ghc == 8.0.1)
cpp-options: -DGHC_801</code></pre></div>
<p>For more info on .cabal flags, see <a href="#item-oh9ytz0p">Define a .cabal flag</a>.</p>