Safe Haskell | Safe |
---|---|
Language | Haskell2010 |
This file provides a generic implementation for counting how many times a data
constructor appears in a value. We use two different type classes in order to
achieve this, called Countable
(for types of kind *) and Countable1
(for
types of kind (* -> *)).
class Countable (a :: *) where count :: a -> ConsMap
class Countable1 (f :: * -> *) where count1 :: f a -> ConsMap
Let us suppose we have the following type definition:
data Tree = Leaf | Node Tree Tree
if we want to count how many times each type constructor appears within a
given value of type Tree
, we need to add the following instance
derivations:
deriving instance Generic Tree instance Countable Tree
Then, we can count type constructors over values of type Tree
:
count (Node (Node Leaf Leaf) (Node Leaf Leaf)) ==> fromList [("Leaf",4),("Node",3)]
Note that, if the Tree
data type definition is available, the `deriving
instance Generic Tree` could be avoided by including Generic at the
type definition deriving clause:
data Tree = Leaf | Node Tree Tree deriving Generic
Countable
requires every subtype of a Countable
data type to be also
Countable
in order to work. If we modify our Tree
definition as
data GTree a = GLeaf | GNode GTree a GTree
then is necessary to add the following instance derivations:
instance deriving Generic a => Generic (GTree a) instance (Generic a, Countable a) => Countable (GTree a)
and the Generic
and Countable
derivations for whatever a
we want to
use. For example, let a
be Bool
(Bool
already has a Generic
instance):
instance Countable Bool
then we can count type constructors on values of type `GTree Bool`
count (GNode (GNode GLeaf False GLeaf) True (GNode GLeaf True GLeaf)) ==> fromList [("False",1),("GLeaf",4),("GNode",3),("True",2)]
but what if we are just interested in counting GLeaf
and GNode
type constructors within values of type `GTree a`? Using Countable
type
class would require to provide (or derive) proper Generic
and Countable
instances for whatever type we instantiate a
with. Fortunately, we can
define a new type class, Countable1
, for types of kind (* -> *) that does
not count type constructors further than the outter data type. Later, we
derive a Countable1
instance for GTree
.
instance Countable1 GTree
count1 (GNode (GNode GLeaf 1 GLeaf) 2 (GNode GLeaf 3 GLeaf)) ==> fromList [("GLeaf",4),("GNode",3)]
count1 (GNode (GNode GLeaf "a" GLeaf) "b" (GNode GLeaf "c" GLeaf)) ==> fromList [("GLeaf",4),("GNode",3)]
Synopsis
- type ConsMap = Map String Int
- class Countable (a :: *) where
- class GCountable f where
- class Countable1 (f :: * -> *) where
- class GCountable1 f where
Documentation
type ConsMap = Map String Int Source #
A map that associates constructors names and the times each one appears within a value.
class GCountable f where Source #
Instances
GCountable (V1 :: * -> *) Source # | |
GCountable (U1 :: * -> *) Source # | |
GCountable (URec a :: * -> *) Source # | |
Countable a => GCountable (K1 i a :: * -> *) Source # | |
(GCountable f, GCountable g) => GCountable (f :+: g) Source # | |
(GCountable f, GCountable g) => GCountable (f :*: g) Source # | |
GCountable f => GCountable (D1 c f) Source # | |
(Constructor c, GCountable f) => GCountable (C1 c f) Source # | |
GCountable f => GCountable (S1 c f) Source # | |
class Countable1 (f :: * -> *) where Source #
class GCountable1 f where Source #
Instances
GCountable1 Par1 Source # | |
GCountable1 (V1 :: * -> *) Source # | |
GCountable1 (U1 :: * -> *) Source # | |
Countable1 f => GCountable1 (Rec1 f) Source # | |
(GCountable1 f, GCountable1 g) => GCountable1 (f :+: g) Source # | |
(GCountable1 f, GCountable1 g) => GCountable1 (f :*: g) Source # | |
GCountable1 f => GCountable1 (D1 c f) Source # | |
(Constructor c, GCountable1 f) => GCountable1 (C1 c f) Source # | |
GCountable1 f => GCountable1 (S1 c f) Source # | |