StrictCheck-0.1.0: StrictCheck: Keep Your Laziness In Check

Safe HaskellNone
LanguageHaskell2010

Test.StrictCheck.Shaped

Contents

Description

This module defines the Shaped typeclass, which is used to generically manipulate values as fixed-points of higher-order functors in order to analyze their structure, e.g. while observing evaluation.

If you just care about testing the strictness of functions over datatypes which are already instances of Shaped, you don't need to use this module.

Important note: To define new instances of Shaped for types which implement Generic, an empty instance will suffice, as all the methods of Shaped can be filled in by generic implementations. For example:

import GHC.Generics as GHC
import Generics.SOP as SOP

data D = C deriving (GHC.Generic)

instance SOP.Generic D
instance SOP.HasDatatypeInfo D

instance Shaped D

Using the DeriveAnyClass extension, this can be shortened to one line:

data D = C deriving (GHC.Generic, SOP.Generic, SOP.HasDatatypeInfo, Shaped)

Manual instances of Shaped are necessary for types which do not or cannot implement GHC's Generic typeclass, such as existential types, abstract types, and GADTs.

This module is heavily based upon the approach in Data.Functor.Foldable, which in turn is modeled after the paper "Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire" (1991) by Erik Meijer, Maarten Fokkinga and Ross Paterson. If you don't yet understand recursion schemes and want to understand this module, it's probably a good idea to familiarize yourself with Data.Functor.Foldable before diving into this higher-order generalization.

Synopsis

Documentation

class Typeable a => Shaped (a :: *) where Source #

When a type a is Shaped, we know how to convert it into a representation parameterized by an arbitrary functor f, so that Shape a f (the "shape of a parameterized by f") is structurally identical to the topmost structure of a, but with f wrapped around any subfields of a.

Note that this is not a recursive representation! The functor f in question wraps the original type of the field and not a Shape of that field.

For instance, the Shape of Either a b might be:

data EitherShape a b f
  = LeftShape  (f a)
  | RightShape (f b)

instance Shaped (Either a b) where
  type Shape (Either a b) = EitherShape a b
  ...

The shape of a primitive type should be isomorphic to the primitive type, with the functor parameter left unused.

Associated Types

type Shape a :: (* -> *) -> * Source #

The Shape of an a is a type isomorphic to the outermost level of structure in an a, parameterized by the functor f, which is wrapped around any fields (of any type) in the original a.

Methods

project :: (forall x. Shaped x => x -> f x) -> a -> Shape a f Source #

Given a function to expand any Shaped x into an f x, expand an a into a Shape a f

That is: convert the top-most level of structure in the given a into a Shape, calling the provided function on each field in the a to produce the f x necessary to fill that hole in the produced Shape a f.

Inverse to embed.

project :: GShaped a => (forall x. Shaped x => x -> f x) -> a -> Shape a f Source #

Given a function to expand any Shaped x into an f x, expand an a into a Shape a f

That is: convert the top-most level of structure in the given a into a Shape, calling the provided function on each field in the a to produce the f x necessary to fill that hole in the produced Shape a f.

Inverse to embed.

embed :: (forall x. Shaped x => f x -> x) -> Shape a f -> a Source #

Given a function to collapse any f x into a Shaped x, collapse a Shape a f into merely an a

That is: eliminate the top-most Shape by calling the provided function on each field in that Shape a f, and using the results to fill in the pieces necessary to build an a.

Inverse to project.

embed :: GShaped a => (forall x. Shaped x => f x -> x) -> Shape a f -> a Source #

Given a function to collapse any f x into a Shaped x, collapse a Shape a f into merely an a

That is: eliminate the top-most Shape by calling the provided function on each field in that Shape a f, and using the results to fill in the pieces necessary to build an a.

Inverse to project.

match :: Shape a f -> Shape a g -> (forall xs. All Shaped xs => Flattened (Shape a) f xs -> Maybe (Flattened (Shape a) g xs) -> result) -> result Source #

Given two Shapes of the same type a but parameterized by potentially different functors f and g, pattern-match on them to expose a uniform view on their fields (a Flattened (Shape a)) to a continuation which may operate on those fields to produce some result

If the two supplied Shapes do not structurally match, only the fields of the first are given to the continuation. If they do match, the fields of the second are also given, along with type-level proof that the types of the two sets of fields align.

This very general operation subsumes equality testing, mapping, zipping, shrinking, and many other structural operations over Shaped things.

It is somewhat difficult to manually write instances for this method, but consulting its generic implementation gMatch may prove helpful.

See Test.StrictCheck.Shaped.Flattened for more information.

match :: GShaped a => Shape a f -> Shape a g -> (forall xs. All Shaped xs => Flattened (Shape a) f xs -> Maybe (Flattened (Shape a) g xs) -> result) -> result Source #

Given two Shapes of the same type a but parameterized by potentially different functors f and g, pattern-match on them to expose a uniform view on their fields (a Flattened (Shape a)) to a continuation which may operate on those fields to produce some result

If the two supplied Shapes do not structurally match, only the fields of the first are given to the continuation. If they do match, the fields of the second are also given, along with type-level proof that the types of the two sets of fields align.

This very general operation subsumes equality testing, mapping, zipping, shrinking, and many other structural operations over Shaped things.

It is somewhat difficult to manually write instances for this method, but consulting its generic implementation gMatch may prove helpful.

See Test.StrictCheck.Shaped.Flattened for more information.

render :: Shape a (K x) -> RenderLevel x Source #

Convert a Shape a whose fields are some unknown constant type into a RenderLevel filled with that type

This is a specialized pretty-printing mechanism which allows for displaying counterexamples in a structured format. See the documentation for RenderLevel.

render :: (GShaped a, HasDatatypeInfo a) => Shape a (K x) -> RenderLevel x Source #

Convert a Shape a whose fields are some unknown constant type into a RenderLevel filled with that type

This is a specialized pretty-printing mechanism which allows for displaying counterexamples in a structured format. See the documentation for RenderLevel.

Instances

Shaped Bool Source # 

Associated Types

type Shape Bool :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Bool -> Shape Bool f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape Bool f -> Bool Source #

match :: Shape Bool f -> Shape Bool g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape Bool) f xs -> Maybe (Flattened * (Shape Bool) g xs) -> result) -> result Source #

render :: Shape Bool (K * x) -> RenderLevel x Source #

Shaped Char Source # 

Associated Types

type Shape Char :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Char -> Shape Char f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape Char f -> Char Source #

match :: Shape Char f -> Shape Char g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape Char) f xs -> Maybe (Flattened * (Shape Char) g xs) -> result) -> result Source #

render :: Shape Char (K * x) -> RenderLevel x Source #

Shaped Double Source # 

Associated Types

type Shape Double :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Double -> Shape Double f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape Double f -> Double Source #

match :: Shape Double f -> Shape Double g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape Double) f xs -> Maybe (Flattened * (Shape Double) g xs) -> result) -> result Source #

render :: Shape Double (K * x) -> RenderLevel x Source #

Shaped Float Source # 

Associated Types

type Shape Float :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Float -> Shape Float f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape Float f -> Float Source #

match :: Shape Float f -> Shape Float g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape Float) f xs -> Maybe (Flattened * (Shape Float) g xs) -> result) -> result Source #

render :: Shape Float (K * x) -> RenderLevel x Source #

Shaped Int Source # 

Associated Types

type Shape Int :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Int -> Shape Int f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape Int f -> Int Source #

match :: Shape Int f -> Shape Int g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape Int) f xs -> Maybe (Flattened * (Shape Int) g xs) -> result) -> result Source #

render :: Shape Int (K * x) -> RenderLevel x Source #

Shaped Integer Source # 

Associated Types

type Shape Integer :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Integer -> Shape Integer f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape Integer f -> Integer Source #

match :: Shape Integer f -> Shape Integer g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape Integer) f xs -> Maybe (Flattened * (Shape Integer) g xs) -> result) -> result Source #

render :: Shape Integer (K * x) -> RenderLevel x Source #

Shaped Ordering Source # 

Associated Types

type Shape Ordering :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Ordering -> Shape Ordering f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape Ordering f -> Ordering Source #

match :: Shape Ordering f -> Shape Ordering g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape Ordering) f xs -> Maybe (Flattened * (Shape Ordering) g xs) -> result) -> result Source #

render :: Shape Ordering (K * x) -> RenderLevel x Source #

Shaped Rational Source # 

Associated Types

type Shape Rational :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Rational -> Shape Rational f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape Rational f -> Rational Source #

match :: Shape Rational f -> Shape Rational g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape Rational) f xs -> Maybe (Flattened * (Shape Rational) g xs) -> result) -> result Source #

render :: Shape Rational (K * x) -> RenderLevel x Source #

Shaped Word Source # 

Associated Types

type Shape Word :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Word -> Shape Word f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape Word f -> Word Source #

match :: Shape Word f -> Shape Word g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape Word) f xs -> Maybe (Flattened * (Shape Word) g xs) -> result) -> result Source #

render :: Shape Word (K * x) -> RenderLevel x Source #

Shaped () Source # 

Associated Types

type Shape () :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> () -> Shape () f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape () f -> () Source #

match :: Shape () f -> Shape () g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape ()) f xs -> Maybe (Flattened * (Shape ()) g xs) -> result) -> result Source #

render :: Shape () (K * x) -> RenderLevel x Source #

Shaped Omega Source # 

Associated Types

type Shape Omega :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Omega -> Shape Omega f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape Omega f -> Omega Source #

match :: Shape Omega f -> Shape Omega g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape Omega) f xs -> Maybe (Flattened * (Shape Omega) g xs) -> result) -> result Source #

render :: Shape Omega (K * x) -> RenderLevel x Source #

Shaped Key Source # 

Associated Types

type Shape Key :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Key -> Shape Key f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape Key f -> Key Source #

match :: Shape Key f -> Shape Key g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape Key) f xs -> Maybe (Flattened * (Shape Key) g xs) -> result) -> result Source #

render :: Shape Key (K * x) -> RenderLevel x Source #

Shaped a => Shaped [a] Source # 

Associated Types

type Shape [a] :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> [a] -> Shape [a] f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape [a] f -> [a] Source #

match :: Shape [a] f -> Shape [a] g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape [a]) f xs -> Maybe (Flattened * (Shape [a]) g xs) -> result) -> result Source #

render :: Shape [a] (K * x) -> RenderLevel x Source #

Shaped a => Shaped (Maybe a) Source # 

Associated Types

type Shape (Maybe a) :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Maybe a -> Shape (Maybe a) f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape (Maybe a) f -> Maybe a Source #

match :: Shape (Maybe a) f -> Shape (Maybe a) g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape (Maybe a)) f xs -> Maybe (Flattened * (Shape (Maybe a)) g xs) -> result) -> result Source #

render :: Shape (Maybe a) (K * x) -> RenderLevel x Source #

(Typeable * a, Eq a, Show a) => Shaped (Complex a) Source # 

Associated Types

type Shape (Complex a) :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Complex a -> Shape (Complex a) f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape (Complex a) f -> Complex a Source #

match :: Shape (Complex a) f -> Shape (Complex a) g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape (Complex a)) f xs -> Maybe (Flattened * (Shape (Complex a)) g xs) -> result) -> result Source #

render :: Shape (Complex a) (K * x) -> RenderLevel x Source #

(Typeable * a, Typeable * b) => Shaped (a -> b) Source # 

Associated Types

type Shape (a -> b) :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> (a -> b) -> Shape (a -> b) f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape (a -> b) f -> a -> b Source #

match :: Shape (a -> b) f -> Shape (a -> b) g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape (a -> b)) f xs -> Maybe (Flattened * (Shape (a -> b)) g xs) -> result) -> result Source #

render :: Shape (a -> b) (K * x) -> RenderLevel x Source #

(Shaped a, Shaped b) => Shaped (Either a b) Source # 

Associated Types

type Shape (Either a b) :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Either a b -> Shape (Either a b) f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape (Either a b) f -> Either a b Source #

match :: Shape (Either a b) f -> Shape (Either a b) g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape (Either a b)) f xs -> Maybe (Flattened * (Shape (Either a b)) g xs) -> result) -> result Source #

render :: Shape (Either a b) (K * x) -> RenderLevel x Source #

(Shaped a, Shaped b) => Shaped (a, b) Source # 

Associated Types

type Shape (a, b) :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> (a, b) -> Shape (a, b) f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape (a, b) f -> (a, b) Source #

match :: Shape (a, b) f -> Shape (a, b) g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape (a, b)) f xs -> Maybe (Flattened * (Shape (a, b)) g xs) -> result) -> result Source #

render :: Shape (a, b) (K * x) -> RenderLevel x Source #

(Shaped v, Shaped k) => Shaped (Map k v) Source # 

Associated Types

type Shape (Map k v) :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> Map k v -> Shape (Map k v) f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape (Map k v) f -> Map k v Source #

match :: Shape (Map k v) f -> Shape (Map k v) g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape (Map k v)) f xs -> Maybe (Flattened * (Shape (Map k v)) g xs) -> result) -> result Source #

render :: Shape (Map k v) (K * x) -> RenderLevel x Source #

(Shaped a, Shaped b, Shaped c) => Shaped (a, b, c) Source # 

Associated Types

type Shape (a, b, c) :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> (a, b, c) -> Shape (a, b, c) f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape (a, b, c) f -> (a, b, c) Source #

match :: Shape (a, b, c) f -> Shape (a, b, c) g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape (a, b, c)) f xs -> Maybe (Flattened * (Shape (a, b, c)) g xs) -> result) -> result Source #

render :: Shape (a, b, c) (K * x) -> RenderLevel x Source #

(Shaped a, Shaped b, Shaped c, Shaped d) => Shaped (a, b, c, d) Source # 

Associated Types

type Shape (a, b, c, d) :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> (a, b, c, d) -> Shape (a, b, c, d) f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape (a, b, c, d) f -> (a, b, c, d) Source #

match :: Shape (a, b, c, d) f -> Shape (a, b, c, d) g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape (a, b, c, d)) f xs -> Maybe (Flattened * (Shape (a, b, c, d)) g xs) -> result) -> result Source #

render :: Shape (a, b, c, d) (K * x) -> RenderLevel x Source #

(Shaped a, Shaped b, Shaped c, Shaped d, Shaped e) => Shaped (a, b, c, d, e) Source # 

Associated Types

type Shape (a, b, c, d, e) :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> (a, b, c, d, e) -> Shape (a, b, c, d, e) f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape (a, b, c, d, e) f -> (a, b, c, d, e) Source #

match :: Shape (a, b, c, d, e) f -> Shape (a, b, c, d, e) g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape (a, b, c, d, e)) f xs -> Maybe (Flattened * (Shape (a, b, c, d, e)) g xs) -> result) -> result Source #

render :: Shape (a, b, c, d, e) (K * x) -> RenderLevel x Source #

(Shaped a, Shaped b, Shaped c, Shaped d, Shaped e, Shaped f) => Shaped (a, b, c, d, e, f) Source # 

Associated Types

type Shape (a, b, c, d, e, f) :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> (a, b, c, d, e, f) -> Shape (a, b, c, d, e, f) f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape (a, b, c, d, e, f) f -> (a, b, c, d, e, f) Source #

match :: Shape (a, b, c, d, e, f) f -> Shape (a, b, c, d, e, f) g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape (a, b, c, d, e, f)) f xs -> Maybe (Flattened * (Shape (a, b, c, d, e, f)) g xs) -> result) -> result Source #

render :: Shape (a, b, c, d, e, f) (K * x) -> RenderLevel x Source #

(Shaped a, Shaped b, Shaped c, Shaped d, Shaped e, Shaped f, Shaped g) => Shaped (a, b, c, d, e, f, g) Source # 

Associated Types

type Shape (a, b, c, d, e, f, g) :: (* -> *) -> * Source #

Methods

project :: (forall x. Shaped x => x -> f x) -> (a, b, c, d, e, f, g) -> Shape (a, b, c, d, e, f, g) f Source #

embed :: (forall x. Shaped x => f x -> x) -> Shape (a, b, c, d, e, f, g) f -> (a, b, c, d, e, f, g) Source #

match :: Shape (a, b, c, d, e, f, g) f -> Shape (a, b, c, d, e, f, g) g -> (forall (xs :: [*]). All * Shaped xs => Flattened * (Shape (a, b, c, d, e, f, g)) f xs -> Maybe (Flattened * (Shape (a, b, c, d, e, f, g)) g xs) -> result) -> result Source #

render :: Shape (a, b, c, d, e, f, g) (K * x) -> RenderLevel x Source #

Fixed-points of Shapes

newtype (f :: * -> *) % (a :: *) :: * where Source #

A value of type f % a has the same structure as an a, but with the structure of the functor f interleaved at every field (including ones of types other than a). Read this type aloud as "a interleaved with f's".

Constructors

Wrap :: f (Shape a ((%) f)) -> f % a 

Instances

Shaped a => Eq (Demand a) #

Demands are compared for equality using eqDemand; see its documentation for details

Methods

(==) :: Demand a -> Demand a -> Bool #

(/=) :: Demand a -> Demand a -> Bool #

Folds and unfolds over fixed-points of Shapes

unwrap :: (f % a) -> f (Shape a ((%) f)) Source #

Look inside a single level of an interleaved f % a. Inverse to the Wrap constructor.

interleave :: (Functor f, Shaped a) => (forall x. x -> f x) -> a -> f % a Source #

Interleave an f-structure at every recursive level of some a, given some way of generating a single level of structure x -> f x.

This is a special case of unfold.

(%) :: forall a f. (Functor f, Shaped a) => (forall x. x -> f x) -> a -> f % a Source #

An infix synonym for interleave

fuse :: (Functor f, Shaped a) => (forall x. f x -> x) -> (f % a) -> a Source #

Fuse the interleaved f-structure out of a recursively interleaved f % a, given some way of fusing a single level f x -> x.

This is a special case of fold.

translate :: forall a f g. Shaped a => (forall x. Shaped x => f x -> g x) -> Shape a f -> Shape a g Source #

Map a function across all the fields in a Shape

This function may change the functor over which the Shape is parameterized. It can assume recursively that all the fields in the Shape are themselves instances of Shaped (which they should be!). This means that you can nest calls to translate recursively.

fold :: forall a f g. (Functor f, Shaped a) => (forall x. Shaped x => f (Shape x g) -> g x) -> (f % a) -> g a Source #

The equivalent of a fold (catamorphism) over recursively Shaped values

Given a function which folds an f containing some Shape x g into a g x, recursively fold any interleaved f % a into a g a.

unfold :: forall a f g. (Functor g, Shaped a) => (forall x. Shaped x => f x -> g (Shape x f)) -> f a -> g % a Source #

The equivalent of an unfold (anamorphism) over recursively Shaped values

Given a function which unfolds an f x into a g containing some Shape x f, corecursively unfold any f a into an interleaved g % a.

unzipWith :: (All Functor [f, g, h], Shaped a) => (forall x. f x -> (g x, h x)) -> (f % a) -> (g % a, h % a) Source #

A higher-kinded unzipWith, operating over interleaved structures

Given a function splitting some f x into a functor-product Product g h x, recursively split an interleaved f % a into two interleaved structures: one built of g-shapes and one of h-shapes.

Note that Product ((%) g) ((%) h) a is isomorphic to (g % a, h % a); to get the latter, pattern-match on the Pair constructor of Product.

Rendering Shaped things as structured text

type QName = (ModuleName, DatatypeName, String) Source #

A QName is a qualified name

Note: > type ModuleName = String > type DatatypeName = String

data Rendered f Source #

Rendered f is the fixed-point of f composed with RenderLevel: it alternates between f shapes and RenderLevels. Usually, f will be the identity functor I, but not always.

Constructors

RWrap (f (RenderLevel (Rendered f))) 

data RenderLevel x Source #

RenderLevel is a functor whose outer shape contains all the information about how to pretty-format the outermost Shape of some value. We use parametricity to make it difficult to construct incorrect render methods, by asking the user merely to produce a single RenderLevel and stitching nested RenderLevels into complete Rendered trees.

Constructors

ConstructorD QName [x]

A prefix constructor, and a list of its fields

InfixD QName Associativity Fixity x x

An infix constructor, its associativity and fixity, and its two fields

RecordD QName [(QName, x)]

A record constructor, and a list of its field names paired with fields

CustomD Fixity [Either (Either String (ModuleName, String)) (Fixity, x)]

A custom pretty-printing representation (i.e. for abstract types), which records a fixity and a list of tokens of three varieties: 1) raw strings, 2) qualified strings (from some module), or 3) actual fields, annotated with their fixity

renderfold :: forall a f. (Shaped a, Functor f) => (f % a) -> Rendered f Source #

TODO: document this strange function

Convert an f % a into a structured pretty-printing representation, suitable for further display/processing

Tools for manually writing instances of Shaped

Implementing Shaped for primitive types

newtype Prim (x :: *) (f :: * -> *) Source #

The Shape of a primitive type should be equivalent to the type itself. However, this does not have the right kind to be used as a Shape.

The Prim newtype solves this problem. By defining the Shape of some primitive type p to be Prim p, you can use the methods projectPrim, embedPrim, matchPrim, and prettyPrim to completely fill in the definition of the Shaped class for a primitive type.

Note: It is only appropriate to use this Shape representation when a type really is primitive, in that it contains no interesting substructure. If you use the Prim representation inappropriately, StrictCheck will not be able to inspect the richer structure of the type in question.

Constructors

Prim x 

Instances

Eq x => Eq (Prim x f) Source # 

Methods

(==) :: Prim x f -> Prim x f -> Bool #

(/=) :: Prim x f -> Prim x f -> Bool #

Num x => Num (Prim x f) Source # 

Methods

(+) :: Prim x f -> Prim x f -> Prim x f #

(-) :: Prim x f -> Prim x f -> Prim x f #

(*) :: Prim x f -> Prim x f -> Prim x f #

negate :: Prim x f -> Prim x f #

abs :: Prim x f -> Prim x f #

signum :: Prim x f -> Prim x f #

fromInteger :: Integer -> Prim x f #

Ord x => Ord (Prim x f) Source # 

Methods

compare :: Prim x f -> Prim x f -> Ordering #

(<) :: Prim x f -> Prim x f -> Bool #

(<=) :: Prim x f -> Prim x f -> Bool #

(>) :: Prim x f -> Prim x f -> Bool #

(>=) :: Prim x f -> Prim x f -> Bool #

max :: Prim x f -> Prim x f -> Prim x f #

min :: Prim x f -> Prim x f -> Prim x f #

Show x => Show (Prim x f) Source # 

Methods

showsPrec :: Int -> Prim x f -> ShowS #

show :: Prim x f -> String #

showList :: [Prim x f] -> ShowS #

unPrim :: Prim x f -> x Source #

Get the wrapped x out of a Prim x f (inverse to the Prim constructor)

projectPrim :: (forall x. Shaped x => x -> f x) -> a -> Prim a f Source #

Generic implementation of project for any primitive type whose Shape is is represented as a Prim newtype

embedPrim :: (forall x. Shaped x => f x -> x) -> Prim a f -> a Source #

Generic implementation of embed for any primitive type whose Shape is is represented as a Prim newtype

matchPrim :: Eq a => Prim a f -> Prim a g -> (forall xs. All Shaped xs => Flattened (Prim a) f xs -> Maybe (Flattened (Prim a) g xs) -> result) -> result Source #

Generic implementation of match for any primitive type whose Shape is is represented as a Prim newtype with an underlying Eq instance

flatPrim :: a -> Flattened (Prim a) g '[] Source #

Helper for writing match instances for primitive types which don't have Eq instance

This generates a Flattened appropriate for using in the implementation of match. For more documentation on how to use this, see the documentation of match.

renderPrim :: Show a => Prim a (K x) -> RenderLevel x Source #

Generic implementation of render for any primitive type whose Shape is is represented as a Prim newtype

renderConstant :: String -> RenderLevel x Source #

Given some string, generate a custom pretty-printing representation which just shows the string

Implementing Shaped for container types

newtype Containing h a f Source #

The Shape of a spine-strict container (i.e. a Map or Set) is the same as a container of demands on its elements. However, this does not have the right kind to be used as a Shape.

The Containing newtype solves this problem. By defining the Shape of some container (C a) to be (C Containing a), you can use the methods projectContainer and embedContainer to implement project and embed for your container type (although you will still need to manually define match and render).

Constructors

Container (h (f a)) 

Instances

Eq (h (f a)) => Eq (Containing k2 k1 h a f) Source # 

Methods

(==) :: Containing k2 k1 h a f -> Containing k2 k1 h a f -> Bool #

(/=) :: Containing k2 k1 h a f -> Containing k2 k1 h a f -> Bool #

Ord (h (f a)) => Ord (Containing k2 k1 h a f) Source # 

Methods

compare :: Containing k2 k1 h a f -> Containing k2 k1 h a f -> Ordering #

(<) :: Containing k2 k1 h a f -> Containing k2 k1 h a f -> Bool #

(<=) :: Containing k2 k1 h a f -> Containing k2 k1 h a f -> Bool #

(>) :: Containing k2 k1 h a f -> Containing k2 k1 h a f -> Bool #

(>=) :: Containing k2 k1 h a f -> Containing k2 k1 h a f -> Bool #

max :: Containing k2 k1 h a f -> Containing k2 k1 h a f -> Containing k2 k1 h a f #

min :: Containing k2 k1 h a f -> Containing k2 k1 h a f -> Containing k2 k1 h a f #

Show (h (f a)) => Show (Containing k2 k1 h a f) Source # 

Methods

showsPrec :: Int -> Containing k2 k1 h a f -> ShowS #

show :: Containing k2 k1 h a f -> String #

showList :: [Containing k2 k1 h a f] -> ShowS #

projectContainer :: (Functor c, Shaped a) => (forall x. Shaped x => x -> f x) -> c a -> Containing c a f Source #

Generic implementation of project for any container type whose Shape is represented as a Containing newtype

embedContainer :: (Functor c, Shaped a) => (forall x. Shaped x => f x -> x) -> Containing c a f -> c a Source #

Generic implementation of embed for any container type whose Shape is represented as a Containing newtype

Generic implementation of the methods of Shaped

type GShaped a = (Generic a, Shape a ~ GShape a, All2 Shaped (Code a), SListI (Code a), All SListI (Code a)) Source #

The collection of constraints necessary for a type to be given a generic implementation of the Shaped methods

newtype GShape a f Source #

The Shape used for generic implementations of Shaped

This wraps a sum-of-products representation from Generics.SOP.

Constructors

GS (NS (NP f) (Code a)) 

gProject :: GShaped a => (forall x. Shaped x => x -> f x) -> a -> Shape a f Source #

Generic project

gEmbed :: GShaped a => (forall x. Shaped x => f x -> x) -> Shape a f -> a Source #

Generic embed

gMatch :: forall a f g result. GShaped a => Shape a f -> Shape a g -> (forall xs. All Shaped xs => Flattened (Shape a) f xs -> Maybe (Flattened (Shape a) g xs) -> result) -> result Source #

Generic match

gRender :: forall a x. (HasDatatypeInfo a, GShaped a) => Shape a (K x) -> RenderLevel x Source #

Generic render