runtime-arbitrary

Last updated: 2017-07-28 13:21:56 +0100

Upstream URL: git clone http://chriswarbo.net/git/runtime-arbitrary.git

Repo

View repository

View issue tracker

Contents of README follows


Obtain data generators at run time, from instances of <code>Arbitrary</code>.

We define one function with the following (simplified) signature

<pre><code>RuntimeArbitrary.getArbGen :: Typeable a => proxy a -> [Gen a]</code></pre>

The <code>proxy</code> type constructor can be anything, whatever makes it easiest to provide the argument. For example <code>[] :: [Foo]</code> is a perfectly good argument, as long as <code>Foo</code> is <code>Typeable</code>.

The resulting list will contain the <code>arbitrary</code> method of the <code>Arbitrary</code> type class, if a suitable instance is in scope at initialisation time (see below). If not, an empty list is returned. (Really, this is a <code>Maybe (Gen a)</code> rather than a <code>[Gen a]</code>, but it’s less verbose to manipulate lists than maybes).

Initialisation is required to find instances, and requires the following line appear somewhere in your module (or one of its imports):

<pre><code>mkIfCxtInstances ''Arbitrary</code></pre>

This is Template Haskell, and uses the <code>IfCxt</code> module from the <code>ifcxt</code> package, so you must have all of those things enabled/imported. This is where the magic happens.

Conceptually, this initialisation line generates, at compile time, a Map of all <code>Arbitrary</code> instances which are in-scope at that point (i.e. available via imports), indexed by type rep. At run time, when we execute a call to <code>getArbGen</code>, it simply looks up the given type rep in this Map, to get the corresponding <code>arbitrary</code> method.

Since Template Haskell cannot (yet) manipulate a module’s imports, this need to initialise “manually” seems unavoidable (if <code>runtime-arbitrary</code> did this initialisation for you, only those instances we decide to import would be available; with no extension mechanism).