model: Derive a model of a data type using Generics

[ bsd3, data, generics, library, reflection ] [ Propose Tags ]

Downloads

Note: This package has metadata revisions in the cabal description newer than included in the tarball. To unpack the package including the revisions, use 'cabal get'.

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.2, 0.2.1, 0.2.4, 0.3, 0.4, 0.4.1, 0.4.2, 0.4.4, 0.5
Change log CHANGELOG
Dependencies base (>=4.8 && <4.11), containers (>=0.5.6.2), deepseq (>=1.4), ListLike (>=4.2.1), pretty (>=1.1.2.0), transformers (>=0.4) [details]
License BSD-3-Clause
Copyright Copyright: (c) 2016 Pasqualino `Titto` Assini
Author Pasqualino `Titto` Assini
Maintainer tittoassini@gmail.com
Revised Revision 1 made by HerbertValerioRiedel at 2019-05-20T20:46:09Z
Category Data, Reflection, Generics
Home page http://github.com/tittoassini/model
Source repo head: git clone https://github.com/tittoassini/model
Uploaded by PasqualinoAssini at 2017-05-16T12:20:27Z
Distributions
Reverse Dependencies 1 direct, 2 indirect [details]
Downloads 6096 total (26 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2017-05-16 [all 1 reports]

Readme for model-0.3

[back to package description]

Build Status Hackage version

With model you can easily derive models of Haskell data types.

Let's see some code.

We need a couple of GHC extensions:

{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}

Import the library:

import Data.Model

To derive a model of a data type we need to make it an instance of the Generic and Model classes.

For data types without parameters, we can do it directly in the deriving clause of the definition:

data Direction = North | South | Center | East | West deriving (Show,Generic,Model)

For data types with parameters we currently need a separate instance declaration for Model:

data Couple a b = Couple a b deriving (Show,Generic)
instance (Model a,Model b) => Model (Couple a b)

Instances for a few common types (Bool,Maybe,Either..) are already predefined.

We use typeModel to get the model for the given type plus its full environment, that's to say the models of all the data types referred to, directly or indirectly by the data type.

We pass the type using a Proxy.

typeModel (Proxy:: Proxy (Couple Direction Bool))
-> TypeModel
->   { typeName =
->       TypeApp
->         (TypeApp
->            (TypeCon
->               QualName
->                 { pkgName = "main" , mdlName = "Main" , locName = "Couple" })
->            (TypeCon
->               QualName
->                 { pkgName = "main" , mdlName = "Main" , locName = "Direction" }))
->         (TypeCon
->            QualName
->              { pkgName = "ghc-prim"
->              , mdlName = "GHC.Types"
->              , locName = "Bool"
->              })
->   , typeEnv =
->       fromList
->         [ ( QualName
->               { pkgName = "ghc-prim" , mdlName = "GHC.Types" , locName = "Bool" }
->           , ADT
->               { declName = "Bool"
->               , declNumParameters = 0
->               , declCons =
->                   Just
->                     (ConTree
->                        Con { constrName = "False" , constrFields = Left [] }
->                        Con { constrName = "True" , constrFields = Left [] })
->               }
->           )
->         , ( QualName
->               { pkgName = "main" , mdlName = "Main" , locName = "Couple" }
->           , ADT
->               { declName = "Couple"
->               , declNumParameters = 2
->               , declCons =
->                   Just
->                     Con
->                       { constrName = "Couple"
->                       , constrFields = Left [ TypeCon (TypVar 0) , TypeCon (TypVar 1) ]
->                       }
->               }
->           )
->         , ( QualName
->               { pkgName = "main" , mdlName = "Main" , locName = "Direction" }
->           , ADT
->               { declName = "Direction"
->               , declNumParameters = 0
->               , declCons =
->                   Just
->                     (ConTree
->                        (ConTree
->                           Con { constrName = "North" , constrFields = Left [] }
->                           Con { constrName = "South" , constrFields = Left [] })
->                        (ConTree
->                           Con { constrName = "Center" , constrFields = Left [] }
->                           (ConTree
->                              Con { constrName = "East" , constrFields = Left [] }
->                              Con { constrName = "West" , constrFields = Left [] })))
->               }
->           )
->         ]
->   }

That's a lot of information, let's show it in a prettier and more compact way:

pPrint $ typeModel (Proxy:: Proxy (Couple Direction Bool))
-> Type:
-> main.Main.Couple main.Main.Direction
->                  ghc-prim.GHC.Types.Bool -> Couple Direction Bool
-> Environment:
-> ghc-prim.GHC.Types.Bool ->  Bool ≡   False
->         | True
-> main.Main.Couple ->  Couple a b ≡ Couple a b
-> main.Main.Direction ->  Direction ≡   North
->              | South
->              | Center
->              | East
->              | West

Data types with symbolic names are also supported:

instance (Model a) => Model [a]
pPrint $ typeModel (Proxy:: Proxy [Bool])
-> Type:
-> ghc-prim.GHC.Types.[] ghc-prim.GHC.Types.Bool -> [] Bool
-> Environment:
-> ghc-prim.GHC.Types.Bool ->  Bool ≡   False
->         | True
-> ghc-prim.GHC.Types.[] ->  [] a ≡   []
->         | : a (ghc-prim.GHC.Types.[] a)

Installation

Get the latest stable version from hackage.

Compatibility

Tested with ghc 7.10.3 and 8.0.2.

Known Bugs and Infelicities

  • No support for variables of higher kind.

    For example, we cannot define a Model instance for Higher:

    data Higher f a = Higher (f a) deriving Generic

    as f has kind *->*:

  • Parametric data types cannot derive Model in the deriving clause and need to define an instance separately

    For example:

    data Couple a b = Couple a b Bool deriving (Generic,Model)

    won't work, we need a separate instance:

    instance (Model a,Model b) => Model (Couple a b)

  • Works incorrectly with data types with more than 9 type variables.