Safe Haskell | None |
---|
A module containing code to generate instances of the Alloy class for you.
Generating Alloy instances by hand would be laborious, complex and error-prone. This module provides instance generation, based on the Scrap Your Boilerplate (Data.Generics) generics that have built-in support in GHC. So you should just need to add
deriving (Data, Typeable)
after all your data-types, then use the functions in this module to generate
some Haskell code with instances of the Alloy classes. The simplest functions
for doing this are writeInstances
and writeInstancesTo
. The tutorial has
examples of using this module.
You do not even have to modify the definitions of your data-types if you are using GHC 6.8.2 or later, you can simply add these lines in your module for generating the instances (assuming the data-type is not hidden during import):
deriving instance Typeable Foo deriving instance Data Foo
That technique, and in fact this module as a whole generates orphan instances. This is generally advised against in Haskell, but it should not cause any problems here.
The primary drawback of Alloy's approach is that it can generate a lot of
type-class instances (generally, the square of the number of types). There
are two ways to control this explosion. Using GenWithOverlapped
tends to
halve the number of instances, at the cost of using a GHC extension. If
you need instances for more than one of Alloy
, AlloyA
and
AlloyARoute
, it is possible to define one based on another, and thus
avoid an entire set of instances altogether. See the alloy-proxy-fd
package on Hackage for more details.
- writeInstances :: GenInstanceConfig -> [GenInstance] -> [String] -> IO ()
- writeInstancesTo :: GenInstanceConfig -> [GenInstance] -> [String] -> FilePath -> IO ()
- justPure :: GenOverlappedOption -> GenInstanceConfig
- allInstances :: GenOverlappedOption -> GenInstanceConfig
- instanceImports :: [String]
- instanceImportsMapSet :: [String]
- instanceImportsVector :: [String]
- data GenInstance
- genInstance :: Data t => t -> GenInstance
- genMapInstance :: forall k v. (Ord k, Data k, Data v) => k -> v -> GenInstance
- genSetInstance :: forall a. (Ord a, Data a) => a -> GenInstance
- genInstances :: GenInstanceConfig -> [GenInstance] -> IO [String]
- languageExtras :: GenOverlappedOption -> String
- genVectorInstance :: forall v. Data v => v -> GenInstance
- data GenOverlappedOption
- data GenClassOption = GenOneClass
- data GenInstanceConfig = GenInstanceConfig {}
Documentation
writeInstances :: GenInstanceConfig -> [GenInstance] -> [String] -> IO ()Source
Generates the instances according to the options and writes it to stdout with the given header (the header is a list of lines without newline characters).
The configuration can be obtained from justPure
(for example) or constructing
the configuration yourself. The list of GenInstance
can be obtained through
genInstance
. The header will generally be something like:
"module FooInstances where" : "import qualified Foo" : instanceImports
writeInstancesTo :: GenInstanceConfig -> [GenInstance] -> [String] -> FilePath -> IO ()Source
Generates the instances according to the options and writes it to the given filename with the given header (the header is a list of lines without newline characters).
justPure :: GenOverlappedOption -> GenInstanceConfigSource
Constructs a configuration that just generates instances for the Alloy
type-class
(not AlloyA
or AlloyARoute
).
allInstances :: GenOverlappedOption -> GenInstanceConfigSource
Constructs instances for all the type-classes: Alloy
, AlloyA
and AlloyARoute
.
This may be quite a lot, see the documentation at the top of this file.
instanceImports :: [String]Source
The lines in the header that form the import statements necessary for the Alloy instances.
instanceImportsMapSet :: [String]Source
Like instanceImports
but also adds the lines needed for maps and sets.
If you use genMapInstance
or genSetInstance
, use this function, otherwise
instanceImports
will suffice.
instanceImportsVector :: [String]Source
Like instanceImportsMapSet
but for Vector
.
data GenInstance Source
A type that represents a generator for instances of a set of types.
genInstance :: Data t => t -> GenInstanceSource
Generates instances for all types within the given type. Therefore you should only need one or two of these calls to cover all of a complex data structure, by calling this on the largest types in your structure. The function is non-strict in its argument, so the easiest way to call it is:
genInstance (undefined :: MyType)
genMapInstance :: forall k v. (Ord k, Data k, Data v) => k -> v -> GenInstanceSource
Generates an instance for the Map
type. Map is a difficult type
because its instance of Data hides its implementation, so we can't actually
use the Data instance to work out what the children are (as we can do for other
algebraic data types). So for every different Map that you want to process
(or that you have inside other types you want to process), you must also call
this function to effectively notify the generation-functions of the existence
of your map. We wish there was an easier, non-hacky way but we can't see one.
genSetInstance :: forall a. (Ord a, Data a) => a -> GenInstanceSource
Generates an instance for the Set
type. See genMapInstance
for
an explanation.
genInstances :: GenInstanceConfig -> [GenInstance] -> IO [String]Source
Generates all the given instances (eliminating any duplicates) with the given options. The return is a list of lines of code. This should then be written to a Haskell module with the appropriate header.
languageExtras :: GenOverlappedOption -> StringSource
The line with a LANGUAGE pragma detailed all the extensions needed. This
is automatically written by writeInstances
and writeInstancesTo
at the top
of the file, but you may want to use it if you are using genInstances
.
genVectorInstance :: forall v. Data v => v -> GenInstanceSource
data GenOverlappedOption Source
The option controlling whether the generated instances can be overlapped.
If you choose GenWithOverlapped
many less instances (around half, in our
experience) will be generated, but you must enable the
overlapping-instances flag in GHC (-XOverlappingInstances in GHC 6.8 and
6.10) when compiling the instances.
data GenClassOption Source
For now, this option has only one setting.