smallcheck-1.2.1.1: Test/SmallCheck/Series.hs
-- vim:fdm=marker:foldtext=foldtext()
--------------------------------------------------------------------
-- |
-- Module : Test.SmallCheck.Series
-- Copyright : (c) Colin Runciman et al.
-- License : BSD3
-- Maintainer: Roman Cheplyaka <roma@ro-che.info>
--
-- You need this module if you want to generate test values of your own
-- types.
--
-- You'll typically need the following extensions:
--
-- >{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
--
-- SmallCheck itself defines data generators for all the data types used
-- by the "Prelude".
--
-- In order to generate values and functions of your own types, you need
-- to make them instances of 'Serial' (for values) and 'CoSerial' (for
-- functions). There are two main ways to do so: using Generics or writing
-- the instances by hand.
--------------------------------------------------------------------
{-# LANGUAGE CPP #-}
#if __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE DefaultSignatures #-}
#endif
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
#if MIN_VERSION_base(4,8,0)
{-# LANGUAGE Safe #-}
#else
{-# LANGUAGE OverlappingInstances #-}
#if __GLASGOW_HASKELL__ >= 704
{-# LANGUAGE Trustworthy #-}
#endif
#endif
#define HASCBOOL MIN_VERSION_base(4,10,0)
module Test.SmallCheck.Series (
-- {{{
-- * Generic instances
-- | The easiest way to create the necessary instances is to use GHC
-- generics (available starting with GHC 7.2.1).
--
-- Here's a complete example:
--
-- >{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
-- >{-# LANGUAGE DeriveGeneric #-}
-- >
-- >import Test.SmallCheck.Series
-- >import GHC.Generics
-- >
-- >data Tree a = Null | Fork (Tree a) a (Tree a)
-- > deriving Generic
-- >
-- >instance Serial m a => Serial m (Tree a)
--
-- Here we enable the @DeriveGeneric@ extension which allows to derive 'Generic'
-- instance for our data type. Then we declare that @Tree@ @a@ is an instance of
-- 'Serial', but do not provide any definitions. This causes GHC to use the
-- default definitions that use the 'Generic' instance.
--
-- One minor limitation of generic instances is that there's currently no
-- way to distinguish newtypes and datatypes. Thus, newtype constructors
-- will also count as one level of depth.
-- * Data Generators
-- | Writing 'Serial' instances for application-specific types is
-- straightforward. You need to define a 'series' generator, typically using
-- @consN@ family of generic combinators where N is constructor arity.
--
-- For example:
--
-- >data Tree a = Null | Fork (Tree a) a (Tree a)
-- >
-- >instance Serial m a => Serial m (Tree a) where
-- > series = cons0 Null \/ cons3 Fork
--
-- For newtypes use 'newtypeCons' instead of 'cons1'.
-- The difference is that 'cons1' is counts as one level of depth, while
-- 'newtypeCons' doesn't affect the depth.
--
-- >newtype Light a = Light a
-- >
-- >instance Serial m a => Serial m (Light a) where
-- > series = newtypeCons Light
--
-- For data types with more than 6 fields define @consN@ as
--
-- >consN f = decDepth $
-- > f <$> series
-- > <~> series
-- > <~> series
-- > <~> ... {- series repeated N times in total -}
-- ** What does @consN@ do, exactly?
-- | @consN@ has type
-- @(Serial t₁, ..., Serial tₙ) => (t₁ -> ... -> tₙ -> t) -> Series t@.
--
-- @consN@ @f@ is a series which, for a given depth \(d > 0\), produces values of the
-- form
--
-- >f x₁ ... xₙ
--
-- where @xₖ@ ranges over all values of type @tₖ@ of depth up to \(d-1\)
-- (as defined by the 'series' functions for @tₖ@).
--
-- @consN@ functions also ensure that xₖ are enumerated in the
-- breadth-first order. Thus, combinations of smaller depth come first
-- (assuming the same is true for @tₖ@).
--
-- If \(d \le 0\), no values are produced.
cons0, cons1, cons2, cons3, cons4, cons5, cons6, newtypeCons,
-- * Function Generators
-- | To generate functions of an application-specific argument type,
-- make the type an instance of 'CoSerial'.
--
-- Again there is a standard pattern, this time using the @altsN@
-- combinators where again N is constructor arity. Here are @Tree@ and
-- @Light@ instances:
--
--
-- >instance CoSerial m a => CoSerial m (Tree a) where
-- > coseries rs =
-- > alts0 rs >>- \z ->
-- > alts3 rs >>- \f ->
-- > return $ \t ->
-- > case t of
-- > Null -> z
-- > Fork t1 x t2 -> f t1 x t2
--
-- >instance CoSerial m a => CoSerial m (Light a) where
-- > coseries rs =
-- > newtypeAlts rs >>- \f ->
-- > return $ \l ->
-- > case l of
-- > Light x -> f x
--
-- For data types with more than 6 fields define @altsN@ as
--
-- >altsN rs = do
-- > rs <- fixDepth rs
-- > decDepthChecked
-- > (constM $ constM $ ... $ constM rs)
-- > (coseries $ coseries $ ... $ coseries rs)
-- > {- constM and coseries are repeated N times each -}
-- ** What does altsN do, exactly?
-- | @altsN@ has type
-- @(Serial t₁, ..., Serial tₙ) => Series t -> Series (t₁ -> ... -> tₙ -> t)@.
--
-- @altsN@ @s@ is a series which, for a given depth \( d \), produces functions of
-- type
--
-- >t₁ -> ... -> tₙ -> t
--
-- If \( d \le 0 \), these are constant functions, one for each value produced
-- by @s@.
--
-- If \( d > 0 \), these functions inspect each of their arguments up to the depth
-- \( d-1 \) (as defined by the 'coseries' functions for the corresponding
-- types) and return values produced by @s@. The depth to which the
-- values are enumerated does not depend on the depth of inspection.
alts0, alts1, alts2, alts3, alts4, alts5, alts6, newtypeAlts,
-- * Basic definitions
Depth, Series, Serial(..), CoSerial(..),
#if __GLASGOW_HASKELL__ >= 702
-- * Generic implementations
genericSeries,
genericCoseries,
#endif
-- * Convenient wrappers
Positive(..), NonNegative(..), NonZero(..), NonEmpty(..),
-- * Other useful definitions
(\/), (><), (<~>), (>>-),
localDepth,
decDepth,
getDepth,
generate,
limit,
listSeries,
list,
listM,
fixDepth,
decDepthChecked,
constM
-- }}}
) where
import Control.Applicative (empty, pure, (<$>), (<|>))
import Control.Monad (Monad, liftM, guard, mzero, mplus, msum, return, (>>), (>>=))
import Control.Monad.Identity (Identity(Identity), runIdentity)
import Control.Monad.Logic (MonadLogic, (>>-), interleave, msplit, observeAllT)
import Control.Monad.Reader (ask, local)
import Data.Bool (Bool (True, False), (&&), (||))
import Data.Char (Char)
import Data.Complex (Complex((:+)))
import Data.Either (Either (Left, Right), either)
import Data.Eq (Eq, (==), (/=))
import Data.Foldable (Foldable)
import Data.Function (($), (.), const)
import Data.Functor (Functor, fmap)
import Data.Functor.Compose (Compose(Compose), getCompose)
import Data.Int (Int, Int8, Int16, Int32, Int64)
import Data.List (intercalate, take, map, length, (++), maximum, sum, unlines, lines, concat)
import qualified Data.List.NonEmpty as NE
import Data.Maybe (Maybe (Just, Nothing), maybe)
import Data.Ord (Ord, Ordering (LT, EQ, GT), max, (<), (>), (>=), compare, (<=))
import Data.Ratio (Ratio, numerator, denominator, (%))
import Data.Traversable (Traversable)
import Data.Tuple (uncurry)
import Data.Void (Void, absurd)
import Data.Word (Word, Word8, Word16, Word32, Word64)
import Numeric.Natural (Natural)
import Prelude (Integer, Real, toRational, Enum, toEnum, fromEnum, Num, (+), (*), Integral, quotRem, toInteger, negate, abs, signum, fromInteger, Bounded, minBound, maxBound, Float, Double, (-), odd, encodeFloat, decodeFloat, realToFrac, seq, subtract)
import Test.SmallCheck.SeriesMonad
import Text.Show (Show, showsPrec, show)
#if MIN_VERSION_base(4,5,0)
import Foreign.C.Types (CFloat(CFloat), CDouble(CDouble), CChar(CChar), CSChar(CSChar), CUChar(CUChar), CShort(CShort), CUShort(CUShort), CInt(CInt), CUInt(CUInt), CLong(CLong), CULong(CULong), CPtrdiff(CPtrdiff), CSize(CSize), CWchar(CWchar), CSigAtomic(CSigAtomic), CLLong(CLLong), CULLong(CULLong), CIntPtr(CIntPtr), CUIntPtr(CUIntPtr), CIntMax(CIntMax), CUIntMax(CUIntMax), CClock(CClock), CTime(CTime), CUSeconds(CUSeconds), CSUSeconds(CSUSeconds))
#endif
#if __GLASGOW_HASKELL__ >= 702
import GHC.Generics (Generic, (:+:)(L1, R1), (:*:)((:*:)), C1, K1(K1), unK1, M1(M1), unM1, U1(U1), V1, Rep, to, from)
#else
import Prelude (RealFloat)
#endif
#if HASCBOOL
import Foreign.C.Types (CBool(CBool))
#endif
------------------------------
-- Main types and classes
------------------------------
--{{{
-- | @since 1.0
class Monad m => Serial m a where
series :: Series m a
#if __GLASGOW_HASKELL__ >= 704
default series :: (Generic a, GSerial m (Rep a)) => Series m a
series = genericSeries
#endif
#if __GLASGOW_HASKELL__ >= 702
-- | @since 1.1.5
genericSeries
:: (Monad m, Generic a, GSerial m (Rep a))
=> Series m a
genericSeries = to <$> gSeries
#endif
-- | @since 1.0
class Monad m => CoSerial m a where
-- | A proper 'coseries' implementation should pass the depth unchanged to
-- its first argument. Doing otherwise will make enumeration of curried
-- functions non-uniform in their arguments.
coseries :: Series m b -> Series m (a->b)
#if __GLASGOW_HASKELL__ >= 704
default coseries :: (Generic a, GCoSerial m (Rep a)) => Series m b -> Series m (a->b)
coseries = genericCoseries
#endif
#if __GLASGOW_HASKELL__ >= 702
-- | @since 1.1.5
genericCoseries
:: (Monad m, Generic a, GCoSerial m (Rep a))
=> Series m b -> Series m (a->b)
genericCoseries rs = (. from) <$> gCoseries rs
#endif
-- }}}
------------------------------
-- Helper functions
------------------------------
-- {{{
-- | A simple series specified by a function from depth to the list of
-- values up to that depth.
--
-- @since 1.0
generate :: (Depth -> [a]) -> Series m a
generate f = do
d <- getDepth
msum $ map return $ f d
-- | Limit a 'Series' to its first @n@ elements.
--
-- @since 1.1.5
limit :: forall m a . Monad m => Int -> Series m a -> Series m a
limit n0 (Series s) = Series $ go n0 s
where
go 0 _ = empty
go n mb1 = do
cons :: Maybe (b, ml b) <- msplit mb1
case cons of
Nothing -> empty
Just (b, mb2) -> return b <|> go (n-1) mb2
suchThat :: Series m a -> (a -> Bool) -> Series m a
suchThat s p = s >>= \x -> if p x then pure x else empty
-- | Given a depth, return the list of values generated by a 'Serial' instance.
--
-- For example, list all integers up to depth 1:
--
-- * @listSeries 1 :: [Int] -- returns [0,1,-1]@
--
-- @since 1.1.2
listSeries :: Serial Identity a => Depth -> [a]
listSeries d = list d series
-- | Return the list of values generated by a 'Series'. Useful for
-- debugging 'Serial' instances.
--
-- Examples:
--
-- * @'list' 3 'series' :: ['Int'] -- returns [0,1,-1,2,-2,3,-3]@
--
-- * @'list' 3 ('series' :: 'Series' 'Data.Functor.Identity' 'Int') -- returns [0,1,-1,2,-2,3,-3]@
--
-- * @'list' 2 'series' :: [['Bool']] -- returns [[],['True'],['False']]@
--
-- The first two are equivalent. The second has a more explicit type binding.
--
-- @since 1.0
list :: Depth -> Series Identity a -> [a]
list d s = runIdentity $ observeAllT $ runSeries d s
-- | Monadic version of 'list'.
--
-- @since 1.1
listM d s = observeAllT $ runSeries d s
-- | Sum (union) of series.
--
-- @since 1.0
infixr 7 \/
(\/) :: Monad m => Series m a -> Series m a -> Series m a
(\/) = interleave
-- | Product of series
--
-- @since 1.0
infixr 8 ><
(><) :: Monad m => Series m a -> Series m b -> Series m (a,b)
a >< b = (,) <$> a <~> b
-- | Fair version of 'Control.Applicative.ap' and 'Control.Applicative.<*>'.
--
-- @since 1.0
infixl 4 <~>
(<~>) :: Monad m => Series m (a -> b) -> Series m a -> Series m b
a <~> b = a >>- (<$> b)
uncurry3 :: (a->b->c->d) -> ((a,b,c)->d)
uncurry3 f (x,y,z) = f x y z
uncurry4 :: (a->b->c->d->e) -> ((a,b,c,d)->e)
uncurry4 f (w,x,y,z) = f w x y z
uncurry5 :: (a->b->c->d->e->f) -> ((a,b,c,d,e)->f)
uncurry5 f (v,w,x,y,z) = f v w x y z
uncurry6 :: (a->b->c->d->e->f->g) -> ((a,b,c,d,e,f)->g)
uncurry6 f (u,v,w,x,y,z) = f u v w x y z
-- | Query the current depth.
--
-- @since 1.0
getDepth :: Series m Depth
getDepth = Series ask
-- | Run a series with a modified depth.
--
-- @since 1.0
localDepth :: (Depth -> Depth) -> Series m a -> Series m a
localDepth f (Series a) = Series $ local f a
-- | Run a 'Series' with the depth decreased by 1.
--
-- If the current depth is less or equal to 0, the result is 'empty'.
--
-- @since 1.0
decDepth :: Series m a -> Series m a
decDepth a = do
checkDepth
localDepth (subtract 1) a
checkDepth :: Series m ()
checkDepth = do
d <- getDepth
guard $ d > 0
-- | @'constM' = 'liftM' 'const'@
--
-- @since 1.1.1
constM :: Monad m => m b -> m (a -> b)
constM = liftM const
-- | Fix the depth of a series at the current level. The resulting series
-- will no longer depend on the \"ambient\" depth.
--
-- @since 1.1.1
fixDepth :: Series m a -> Series m (Series m a)
fixDepth s = getDepth >>= \d -> return $ localDepth (const d) s
-- | If the current depth is 0, evaluate the first argument. Otherwise,
-- evaluate the second argument with decremented depth.
--
-- @since 1.1.1
decDepthChecked :: Series m a -> Series m a -> Series m a
decDepthChecked b r = do
d <- getDepth
if d <= 0
then b
else decDepth r
unwind :: MonadLogic m => m a -> m [a]
unwind a =
msplit a >>=
maybe (return []) (\(x,a') -> (x:) `liftM` unwind a')
-- }}}
------------------------------
-- cons* and alts* functions
------------------------------
-- {{{
-- | @since 1.0
cons0 :: a -> Series m a
cons0 x = decDepth $ pure x
-- | @since 1.0
cons1 :: Serial m a => (a->b) -> Series m b
cons1 f = decDepth $ f <$> series
-- | Same as 'cons1', but preserves the depth.
--
-- @since 1.0
newtypeCons :: Serial m a => (a->b) -> Series m b
newtypeCons f = f <$> series
-- | @since 1.0
cons2 :: (Serial m a, Serial m b) => (a->b->c) -> Series m c
cons2 f = decDepth $ f <$> series <~> series
-- | @since 1.0
cons3 :: (Serial m a, Serial m b, Serial m c) =>
(a->b->c->d) -> Series m d
cons3 f = decDepth $
f <$> series
<~> series
<~> series
-- | @since 1.0
cons4 :: (Serial m a, Serial m b, Serial m c, Serial m d) =>
(a->b->c->d->e) -> Series m e
cons4 f = decDepth $
f <$> series
<~> series
<~> series
<~> series
-- | @since 1.2.0
cons5 :: (Serial m a, Serial m b, Serial m c, Serial m d, Serial m e) =>
(a->b->c->d->e->f) -> Series m f
cons5 f = decDepth $
f <$> series
<~> series
<~> series
<~> series
<~> series
-- | @since 1.2.0
cons6 :: (Serial m a, Serial m b, Serial m c, Serial m d, Serial m e, Serial m f) =>
(a->b->c->d->e->f->g) -> Series m g
cons6 f = decDepth $
f <$> series
<~> series
<~> series
<~> series
<~> series
<~> series
-- | @since 1.0
alts0 :: Series m a -> Series m a
alts0 s = s
-- | @since 1.0
alts1 :: CoSerial m a => Series m b -> Series m (a->b)
alts1 rs = do
rs <- fixDepth rs
decDepthChecked (constM rs) (coseries rs)
-- | @since 1.0
alts2
:: (CoSerial m a, CoSerial m b)
=> Series m c -> Series m (a->b->c)
alts2 rs = do
rs <- fixDepth rs
decDepthChecked
(constM $ constM rs)
(coseries $ coseries rs)
-- | @since 1.0
alts3 :: (CoSerial m a, CoSerial m b, CoSerial m c) =>
Series m d -> Series m (a->b->c->d)
alts3 rs = do
rs <- fixDepth rs
decDepthChecked
(constM $ constM $ constM rs)
(coseries $ coseries $ coseries rs)
-- | @since 1.0
alts4 :: (CoSerial m a, CoSerial m b, CoSerial m c, CoSerial m d) =>
Series m e -> Series m (a->b->c->d->e)
alts4 rs = do
rs <- fixDepth rs
decDepthChecked
(constM $ constM $ constM $ constM rs)
(coseries $ coseries $ coseries $ coseries rs)
-- | @since 1.2.0
alts5 :: (CoSerial m a, CoSerial m b, CoSerial m c, CoSerial m d, CoSerial m e) =>
Series m f -> Series m (a->b->c->d->e->f)
alts5 rs = do
rs <- fixDepth rs
decDepthChecked
(constM $ constM $ constM $ constM $ constM rs)
(coseries $ coseries $ coseries $ coseries $ coseries rs)
-- | @since 1.2.0
alts6 :: (CoSerial m a, CoSerial m b, CoSerial m c, CoSerial m d, CoSerial m e, CoSerial m f) =>
Series m g -> Series m (a->b->c->d->e->f->g)
alts6 rs = do
rs <- fixDepth rs
decDepthChecked
(constM $ constM $ constM $ constM $ constM $ constM rs)
(coseries $ coseries $ coseries $ coseries $ coseries $ coseries rs)
-- | Same as 'alts1', but preserves the depth.
--
-- @since 1.0
newtypeAlts :: CoSerial m a => Series m b -> Series m (a->b)
newtypeAlts = coseries
-- }}}
------------------------------
-- Generic instances
------------------------------
-- {{{
class GSerial m f where
gSeries :: Series m (f a)
class GCoSerial m f where
gCoseries :: Series m b -> Series m (f a -> b)
#if __GLASGOW_HASKELL__ >= 702
instance {-# OVERLAPPABLE #-} GSerial m f => GSerial m (M1 i c f) where
gSeries = M1 <$> gSeries
{-# INLINE gSeries #-}
instance GCoSerial m f => GCoSerial m (M1 i c f) where
gCoseries rs = (. unM1) <$> gCoseries rs
{-# INLINE gCoseries #-}
instance Serial m c => GSerial m (K1 i c) where
gSeries = K1 <$> series
{-# INLINE gSeries #-}
instance CoSerial m c => GCoSerial m (K1 i c) where
gCoseries rs = (. unK1) <$> coseries rs
{-# INLINE gCoseries #-}
instance GSerial m U1 where
gSeries = pure U1
{-# INLINE gSeries #-}
instance GCoSerial m U1 where
gCoseries rs = constM rs
{-# INLINE gCoseries #-}
instance GSerial m V1 where
gSeries = mzero
{-# INLINE gSeries #-}
instance GCoSerial m V1 where
gCoseries = const $ return (\a -> a `seq` let x = x in x)
{-# INLINE gCoseries #-}
instance (Monad m, GSerial m a, GSerial m b) => GSerial m (a :*: b) where
gSeries = (:*:) <$> gSeries <~> gSeries
{-# INLINE gSeries #-}
instance (Monad m, GCoSerial m a, GCoSerial m b) => GCoSerial m (a :*: b) where
gCoseries rs = uncur <$> gCoseries (gCoseries rs)
where
uncur f (x :*: y) = f x y
{-# INLINE gCoseries #-}
instance (Monad m, GSerial m a, GSerial m b) => GSerial m (a :+: b) where
gSeries = (L1 <$> gSeries) `interleave` (R1 <$> gSeries)
{-# INLINE gSeries #-}
instance (Monad m, GCoSerial m a, GCoSerial m b) => GCoSerial m (a :+: b) where
gCoseries rs =
gCoseries rs >>- \f ->
gCoseries rs >>- \g ->
return $
\e -> case e of
L1 x -> f x
R1 y -> g y
{-# INLINE gCoseries #-}
instance {-# OVERLAPPING #-} GSerial m f => GSerial m (C1 c f) where
gSeries = M1 <$> decDepth gSeries
{-# INLINE gSeries #-}
#endif
-- }}}
------------------------------
-- Instances for basic types
------------------------------
-- {{{
instance Monad m => Serial m () where
series = return ()
instance Monad m => CoSerial m () where
coseries rs = constM rs
instance Monad m => Serial m Integer where series = unM <$> series
instance Monad m => CoSerial m Integer where coseries = fmap (. M) . coseries
-- | @since 1.1.3
instance Monad m => Serial m Natural where series = unN <$> series
-- | @since 1.1.3
instance Monad m => CoSerial m Natural where coseries = fmap (. N) . coseries
instance Monad m => Serial m Int where series = unM <$> series
instance Monad m => CoSerial m Int where coseries = fmap (. M) . coseries
-- | @since 1.1.3
instance Monad m => Serial m Word where series = unN <$> series
-- | @since 1.1.3
instance Monad m => CoSerial m Word where coseries = fmap (. N) . coseries
-- | @since 1.1.4
instance Monad m => Serial m Int8 where series = unM <$> series
-- | @since 1.1.4
instance Monad m => CoSerial m Int8 where coseries = fmap (. M) . coseries
-- | @since 1.1.4
instance Monad m => Serial m Word8 where series = unN <$> series
-- | @since 1.1.4
instance Monad m => CoSerial m Word8 where coseries = fmap (. N) . coseries
-- | @since 1.1.4
instance Monad m => Serial m Int16 where series = unM <$> series
-- | @since 1.1.4
instance Monad m => CoSerial m Int16 where coseries = fmap (. M) . coseries
-- | @since 1.1.4
instance Monad m => Serial m Word16 where series = unN <$> series
-- | @since 1.1.4
instance Monad m => CoSerial m Word16 where coseries = fmap (. N) . coseries
-- | @since 1.1.4
instance Monad m => Serial m Int32 where series = unM <$> series
-- | @since 1.1.4
instance Monad m => CoSerial m Int32 where coseries = fmap (. M) . coseries
-- | @since 1.1.4
instance Monad m => Serial m Word32 where series = unN <$> series
-- | @since 1.1.4
instance Monad m => CoSerial m Word32 where coseries = fmap (. N) . coseries
-- | @since 1.1.4
instance Monad m => Serial m Int64 where series = unM <$> series
-- | @since 1.1.4
instance Monad m => CoSerial m Int64 where coseries = fmap (. M) . coseries
-- | @since 1.1.4
instance Monad m => Serial m Word64 where series = unN <$> series
-- | @since 1.1.4
instance Monad m => CoSerial m Word64 where coseries = fmap (. N) . coseries
-- | 'N' is a wrapper for 'Integral' types that causes only non-negative values
-- to be generated. Generated functions of type @N a -> b@ do not distinguish
-- different negative values of @a@.
newtype N a = N { unN :: a } deriving (Eq, Ord, Show)
instance Real a => Real (N a) where
toRational (N x) = toRational x
instance Enum a => Enum (N a) where
toEnum x = N (toEnum x)
fromEnum (N x) = fromEnum x
instance Num a => Num (N a) where
N x + N y = N (x + y)
N x * N y = N (x * y)
negate (N x) = N (negate x)
abs (N x) = N (abs x)
signum (N x) = N (signum x)
fromInteger x = N (fromInteger x)
instance Integral a => Integral (N a) where
quotRem (N x) (N y) = (N q, N r)
where
(q, r) = x `quotRem` y
toInteger (N x) = toInteger x
instance (Num a, Enum a, Serial m a) => Serial m (N a) where
series = generate $ \d -> take (d+1) [0..]
instance (Integral a, Monad m) => CoSerial m (N a) where
coseries rs =
-- This is a recursive function, because @alts1 rs@ typically calls
-- back to 'coseries' (but with lower depth).
--
-- The recursion stops when depth == 0. Then alts1 produces a constant
-- function, and doesn't call back to 'coseries'.
alts0 rs >>- \z ->
alts1 rs >>- \f ->
return $ \(N i) ->
if i > 0
then f (N $ i-1)
else z
-- | 'M' is a helper type to generate values of a signed type of increasing magnitude.
newtype M a = M { unM :: a } deriving (Eq, Ord, Show)
instance Real a => Real (M a) where
toRational (M x) = toRational x
instance Enum a => Enum (M a) where
toEnum x = M (toEnum x)
fromEnum (M x) = fromEnum x
instance Num a => Num (M a) where
M x + M y = M (x + y)
M x * M y = M (x * y)
negate (M x) = M (negate x)
abs (M x) = M (abs x)
signum (M x) = M (signum x)
fromInteger x = M (fromInteger x)
instance Integral a => Integral (M a) where
quotRem (M x) (M y) = (M q, M r)
where
(q, r) = x `quotRem` y
toInteger (M x) = toInteger x
instance (Num a, Enum a, Monad m) => Serial m (M a) where
series = others `interleave` positives
where positives = generate $ \d -> take d [1..]
others = generate $ \d -> take (d+1) [0,-1..]
instance (Ord a, Num a, Monad m) => CoSerial m (M a) where
coseries rs =
alts0 rs >>- \z ->
alts1 rs >>- \f ->
alts1 rs >>- \g ->
pure $ \ i -> case compare i 0 of
GT -> f (M (i - 1))
LT -> g (M (abs i - 1))
EQ -> z
instance Monad m => Serial m Float where
series =
series >>- \(sig, exp) ->
guard (odd sig || sig==0 && exp==0) >>
return (encodeFloat sig exp)
instance Monad m => CoSerial m Float where
coseries rs =
coseries rs >>- \f ->
return $ f . decodeFloat
instance Monad m => Serial m Double where
series = (realToFrac :: Float -> Double) <$> series
instance Monad m => CoSerial m Double where
coseries rs =
(. (realToFrac :: Double -> Float)) <$> coseries rs
-- | @since 1.1
instance (Integral i, Serial m i) => Serial m (Ratio i) where
series = pairToRatio <$> series
where
pairToRatio (n, Positive d) = n % d
-- | @since 1.1
instance (Integral i, CoSerial m i) => CoSerial m (Ratio i) where
coseries rs = (. ratioToPair) <$> coseries rs
where
ratioToPair r = (numerator r, denominator r)
instance Monad m => Serial m Char where
series = generate $ \d -> take (d+1) ['a'..'z']
instance Monad m => CoSerial m Char where
coseries rs =
coseries rs >>- \f ->
return $ \c -> f (N (fromEnum c - fromEnum 'a'))
instance (Serial m a, Serial m b) => Serial m (a,b) where
series = cons2 (,)
instance (CoSerial m a, CoSerial m b) => CoSerial m (a,b) where
coseries rs = uncurry <$> alts2 rs
instance (Serial m a, Serial m b, Serial m c) => Serial m (a,b,c) where
series = cons3 (,,)
instance (CoSerial m a, CoSerial m b, CoSerial m c) => CoSerial m (a,b,c) where
coseries rs = uncurry3 <$> alts3 rs
instance (Serial m a, Serial m b, Serial m c, Serial m d) => Serial m (a,b,c,d) where
series = cons4 (,,,)
instance (CoSerial m a, CoSerial m b, CoSerial m c, CoSerial m d) => CoSerial m (a,b,c,d) where
coseries rs = uncurry4 <$> alts4 rs
-- | @since 1.2.0
instance (Serial m a, Serial m b, Serial m c, Serial m d, Serial m e) => Serial m (a,b,c,d,e) where
series = cons5 (,,,,)
-- | @since 1.2.0
instance (CoSerial m a, CoSerial m b, CoSerial m c, CoSerial m d, CoSerial m e) => CoSerial m (a,b,c,d,e) where
coseries rs = uncurry5 <$> alts5 rs
-- | @since 1.2.0
instance (Serial m a, Serial m b, Serial m c, Serial m d, Serial m e, Serial m f) => Serial m (a,b,c,d,e,f) where
series = cons6 (,,,,,)
-- | @since 1.2.0
instance (CoSerial m a, CoSerial m b, CoSerial m c, CoSerial m d, CoSerial m e, CoSerial m f) => CoSerial m (a,b,c,d,e,f) where
coseries rs = uncurry6 <$> alts6 rs
instance Monad m => Serial m Bool where
series = cons0 True \/ cons0 False
instance Monad m => CoSerial m Bool where
coseries rs =
rs >>- \r1 ->
rs >>- \r2 ->
return $ \x -> if x then r1 else r2
-- | @since 1.2.1
instance Monad m => Serial m Ordering where
series = cons0 LT \/ cons0 EQ \/ cons0 GT
-- | @since 1.2.1
instance Monad m => CoSerial m Ordering where
coseries rs =
rs >>- \r1 ->
rs >>- \r2 ->
rs >>- \r3 ->
pure $ \x -> case x of
LT -> r1
EQ -> r2
GT -> r3
instance (Serial m a) => Serial m (Maybe a) where
series = cons0 Nothing \/ cons1 Just
instance (CoSerial m a) => CoSerial m (Maybe a) where
coseries rs =
maybe <$> alts0 rs <~> alts1 rs
instance (Serial m a, Serial m b) => Serial m (Either a b) where
series = cons1 Left \/ cons1 Right
instance (CoSerial m a, CoSerial m b) => CoSerial m (Either a b) where
coseries rs =
either <$> alts1 rs <~> alts1 rs
instance Serial m a => Serial m [a] where
series = cons0 [] \/ cons2 (:)
instance CoSerial m a => CoSerial m [a] where
coseries rs =
alts0 rs >>- \y ->
alts2 rs >>- \f ->
return $ \xs -> case xs of [] -> y; x:xs' -> f x xs'
-- | @since 1.2.0
instance Serial m a => Serial m (NE.NonEmpty a) where
series = cons2 (NE.:|)
-- | @since 1.2.0
instance CoSerial m a => CoSerial m (NE.NonEmpty a) where
coseries rs =
alts2 rs >>- \f ->
return $ \(x NE.:| xs') -> f x xs'
#if MIN_VERSION_base(4,4,0)
-- | @since 1.2.0
instance Serial m a => Serial m (Complex a) where
#else
-- | @since 1.2.0
instance (RealFloat a, Serial m a) => Serial m (Complex a) where
#endif
series = cons2 (:+)
#if MIN_VERSION_base(4,4,0)
-- | @since 1.2.0
instance CoSerial m a => CoSerial m (Complex a) where
#else
-- | @since 1.2.0
instance (RealFloat a, CoSerial m a) => CoSerial m (Complex a) where
#endif
coseries rs =
alts2 rs >>- \f ->
return $ \(x :+ xs') -> f x xs'
-- | @since 1.2.0
instance Monad m => Serial m Void where
series = mzero
-- | @since 1.2.0
instance Monad m => CoSerial m Void where
coseries = const $ return absurd
instance (CoSerial m a, Serial m b) => Serial m (a->b) where
series = coseries series
-- Thanks to Ralf Hinze for the definition of coseries
-- using the nest auxiliary.
instance (Serial m a, CoSerial m a, Serial m b, CoSerial m b) => CoSerial m (a->b) where
coseries r = do
args <- unwind series
g <- nest r args
return $ \f -> g $ map f args
where
nest :: forall a b m c . (Serial m b, CoSerial m b) => Series m c -> [a] -> Series m ([b] -> c)
nest rs args = do
case args of
[] -> const `liftM` rs
_:rest -> do
let sf = coseries $ nest rs rest
f <- sf
return $ \(b:bs) -> f b bs
-- show the extension of a function (in part, bounded both by
-- the number and depth of arguments)
instance (Serial Identity a, Show a, Show b) => Show (a -> b) where
show f =
if maxarheight == 1
&& sumarwidth + length ars * length "->;" < widthLimit then
"{"++
intercalate ";" [a++"->"++r | (a,r) <- ars]
++"}"
else
concat $ [a++"->\n"++indent r | (a,r) <- ars]
where
ars = take lengthLimit [ (show x, show (f x))
| x <- list depthLimit series ]
maxarheight = maximum [ max (height a) (height r)
| (a,r) <- ars ]
sumarwidth = sum [ length a + length r
| (a,r) <- ars]
indent = unlines . map (" "++) . lines
height = length . lines
(widthLimit,lengthLimit,depthLimit) = (80,20,3)::(Int,Int,Depth)
-- | @since 1.2.0
instance (Monad m, Serial m (f (g a))) => Serial m (Compose f g a) where
series = Compose <$> series
-- | @since 1.2.0
instance (Monad m, CoSerial m (f (g a))) => CoSerial m (Compose f g a) where
coseries = fmap (. getCompose) . coseries
-- }}}
------------------------------
-- Convenient wrappers
------------------------------
-- {{{
--------------------------------------------------------------------------
-- | 'Positive' @x@ guarantees that \( x > 0 \).
--
-- @since 1.0
newtype Positive a = Positive { getPositive :: a }
deriving
( Eq
, Ord
, Functor -- ^ @since 1.2.0
, Foldable -- ^ @since 1.2.0
, Traversable -- ^ @since 1.2.0
)
instance Real a => Real (Positive a) where
toRational (Positive x) = toRational x
-- | @since 1.2.0
instance (Num a, Bounded a) => Bounded (Positive a) where
minBound = Positive 1
maxBound = Positive (maxBound :: a)
instance Enum a => Enum (Positive a) where
toEnum x = Positive (toEnum x)
fromEnum (Positive x) = fromEnum x
instance Num a => Num (Positive a) where
Positive x + Positive y = Positive (x + y)
Positive x * Positive y = Positive (x * y)
negate (Positive x) = Positive (negate x)
abs (Positive x) = Positive (abs x)
signum (Positive x) = Positive (signum x)
fromInteger x = Positive (fromInteger x)
instance Integral a => Integral (Positive a) where
quotRem (Positive x) (Positive y) = (Positive q, Positive r)
where
(q, r) = x `quotRem` y
toInteger (Positive x) = toInteger x
instance (Num a, Ord a, Serial m a) => Serial m (Positive a) where
series = Positive <$> series `suchThat` (> 0)
instance Show a => Show (Positive a) where
showsPrec n (Positive x) = showsPrec n x
-- | 'NonNegative' @x@ guarantees that \( x \ge 0 \).
--
-- @since 1.0
newtype NonNegative a = NonNegative { getNonNegative :: a }
deriving
( Eq
, Ord
, Functor -- ^ @since 1.2.0
, Foldable -- ^ @since 1.2.0
, Traversable -- ^ @since 1.2.0
)
instance Real a => Real (NonNegative a) where
toRational (NonNegative x) = toRational x
-- | @since 1.2.0
instance (Num a, Bounded a) => Bounded (NonNegative a) where
minBound = NonNegative 0
maxBound = NonNegative (maxBound :: a)
instance Enum a => Enum (NonNegative a) where
toEnum x = NonNegative (toEnum x)
fromEnum (NonNegative x) = fromEnum x
instance Num a => Num (NonNegative a) where
NonNegative x + NonNegative y = NonNegative (x + y)
NonNegative x * NonNegative y = NonNegative (x * y)
negate (NonNegative x) = NonNegative (negate x)
abs (NonNegative x) = NonNegative (abs x)
signum (NonNegative x) = NonNegative (signum x)
fromInteger x = NonNegative (fromInteger x)
instance Integral a => Integral (NonNegative a) where
quotRem (NonNegative x) (NonNegative y) = (NonNegative q, NonNegative r)
where
(q, r) = x `quotRem` y
toInteger (NonNegative x) = toInteger x
instance (Num a, Ord a, Serial m a) => Serial m (NonNegative a) where
series = NonNegative <$> series `suchThat` (>= 0)
instance Show a => Show (NonNegative a) where
showsPrec n (NonNegative x) = showsPrec n x
-- | 'NonZero' @x@ guarantees that \( x \ne 0 \).
--
-- @since 1.2.0
newtype NonZero a = NonZero { getNonZero :: a }
deriving (Eq, Ord, Functor, Foldable, Traversable)
instance Real a => Real (NonZero a) where
toRational (NonZero x) = toRational x
instance (Eq a, Num a, Bounded a) => Bounded (NonZero a) where
minBound = let x = minBound in NonZero (if x == 0 then 1 else x)
maxBound = let x = maxBound in NonZero (if x == 0 then -1 else x)
instance Enum a => Enum (NonZero a) where
toEnum x = NonZero (toEnum x)
fromEnum (NonZero x) = fromEnum x
instance Num a => Num (NonZero a) where
NonZero x + NonZero y = NonZero (x + y)
NonZero x * NonZero y = NonZero (x * y)
negate (NonZero x) = NonZero (negate x)
abs (NonZero x) = NonZero (abs x)
signum (NonZero x) = NonZero (signum x)
fromInteger x = NonZero (fromInteger x)
instance Integral a => Integral (NonZero a) where
quotRem (NonZero x) (NonZero y) = (NonZero q, NonZero r)
where
(q, r) = x `quotRem` y
toInteger (NonZero x) = toInteger x
instance (Num a, Ord a, Serial m a) => Serial m (NonZero a) where
series = NonZero <$> series `suchThat` (/= 0)
instance Show a => Show (NonZero a) where
showsPrec n (NonZero x) = showsPrec n x
-- | 'NonEmpty' @xs@ guarantees that @xs@ is not null.
--
-- @since 1.1
newtype NonEmpty a = NonEmpty { getNonEmpty :: [a] }
instance (Serial m a) => Serial m (NonEmpty a) where
series = NonEmpty <$> cons2 (:)
instance Show a => Show (NonEmpty a) where
showsPrec n (NonEmpty x) = showsPrec n x
-- }}}
------------------------------
-- Foreign.C.Types
------------------------------
-- {{{
#if MIN_VERSION_base(4,5,0)
-- | @since 1.2.0
instance Monad m => Serial m CFloat where
series = newtypeCons CFloat
-- | @since 1.2.0
instance Monad m => CoSerial m CFloat where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CFloat x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CDouble where
series = newtypeCons CDouble
-- | @since 1.2.0
instance Monad m => CoSerial m CDouble where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CDouble x -> f x
#if HASCBOOL
-- | @since 1.2.0
instance Monad m => Serial m CBool where
series = newtypeCons CBool
-- | @since 1.2.0
instance Monad m => CoSerial m CBool where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CBool x -> f x
#endif
-- | @since 1.2.0
instance Monad m => Serial m CChar where
series = newtypeCons CChar
-- | @since 1.2.0
instance Monad m => CoSerial m CChar where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CChar x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CSChar where
series = newtypeCons CSChar
-- | @since 1.2.0
instance Monad m => CoSerial m CSChar where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CSChar x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CUChar where
series = newtypeCons CUChar
-- | @since 1.2.0
instance Monad m => CoSerial m CUChar where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CUChar x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CShort where
series = newtypeCons CShort
-- | @since 1.2.0
instance Monad m => CoSerial m CShort where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CShort x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CUShort where
series = newtypeCons CUShort
-- | @since 1.2.0
instance Monad m => CoSerial m CUShort where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CUShort x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CInt where
series = newtypeCons CInt
-- | @since 1.2.0
instance Monad m => CoSerial m CInt where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CInt x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CUInt where
series = newtypeCons CUInt
-- | @since 1.2.0
instance Monad m => CoSerial m CUInt where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CUInt x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CLong where
series = newtypeCons CLong
-- | @since 1.2.0
instance Monad m => CoSerial m CLong where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CLong x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CULong where
series = newtypeCons CULong
-- | @since 1.2.0
instance Monad m => CoSerial m CULong where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CULong x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CPtrdiff where
series = newtypeCons CPtrdiff
-- | @since 1.2.0
instance Monad m => CoSerial m CPtrdiff where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CPtrdiff x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CSize where
series = newtypeCons CSize
-- | @since 1.2.0
instance Monad m => CoSerial m CSize where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CSize x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CWchar where
series = newtypeCons CWchar
-- | @since 1.2.0
instance Monad m => CoSerial m CWchar where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CWchar x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CSigAtomic where
series = newtypeCons CSigAtomic
-- | @since 1.2.0
instance Monad m => CoSerial m CSigAtomic where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CSigAtomic x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CLLong where
series = newtypeCons CLLong
-- | @since 1.2.0
instance Monad m => CoSerial m CLLong where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CLLong x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CULLong where
series = newtypeCons CULLong
-- | @since 1.2.0
instance Monad m => CoSerial m CULLong where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CULLong x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CIntPtr where
series = newtypeCons CIntPtr
-- | @since 1.2.0
instance Monad m => CoSerial m CIntPtr where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CIntPtr x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CUIntPtr where
series = newtypeCons CUIntPtr
-- | @since 1.2.0
instance Monad m => CoSerial m CUIntPtr where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CUIntPtr x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CIntMax where
series = newtypeCons CIntMax
-- | @since 1.2.0
instance Monad m => CoSerial m CIntMax where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CIntMax x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CUIntMax where
series = newtypeCons CUIntMax
-- | @since 1.2.0
instance Monad m => CoSerial m CUIntMax where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CUIntMax x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CClock where
series = newtypeCons CClock
-- | @since 1.2.0
instance Monad m => CoSerial m CClock where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CClock x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CTime where
series = newtypeCons CTime
-- | @since 1.2.0
instance Monad m => CoSerial m CTime where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CTime x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CUSeconds where
series = newtypeCons CUSeconds
-- | @since 1.2.0
instance Monad m => CoSerial m CUSeconds where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CUSeconds x -> f x
-- | @since 1.2.0
instance Monad m => Serial m CSUSeconds where
series = newtypeCons CSUSeconds
-- | @since 1.2.0
instance Monad m => CoSerial m CSUSeconds where
coseries rs = newtypeAlts rs >>- \f -> return $ \l -> case l of CSUSeconds x -> f x
#endif
-- }}}