    {-# OPTIONS_HADDOCK not-home #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    module Hedgehog.Internal.Range (
      -- * Size
        Size(..)

      -- * Range
      , Range(..)
      , origin
      , bounds
      , lowerBound
      , upperBound

      -- * Constant
      , singleton
      , constant
      , constantFrom
      , constantBounded

      -- * Linear
      , linear
      , linearFrom
      , linearFrac
      , linearFracFrom
      , linearBounded

      -- * Exponential
      , exponential
      , exponentialFrom
      , exponentialBounded
      , exponentialFloat
      , exponentialFloatFrom

      -- * Internal
      -- $internal
      , clamp
      , scaleLinear
      , scaleLinearFrac
      , scaleExponential
      , scaleExponentialFloat
      ) where

    import           Data.Bifunctor (bimap)

    import           Prelude hiding (minimum, maximum)

    -- $setup
    -- >>> import Data.Int (Int8)
    -- >>> let x = 3

    -- | Tests are parameterized by the size of the randomly-generated data. The
    --   meaning of a 'Size' value depends on the particular generator used, but
    --   it must always be a number between 0 and 99 inclusive.
    --
    newtype Size =
      Size {
          Size -> Int
    unSize :: Int
        } deriving (Size -> Size -> Bool
    (Size -> Size -> Bool) -> (Size -> Size -> Bool) -> Eq Size
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Size -> Size -> Bool
    == :: Size -> Size -> Bool
    $c/= :: Size -> Size -> Bool
    /= :: Size -> Size -> Bool
    Eq, Eq Size
    Eq Size =>
    (Size -> Size -> Ordering)
    -> (Size -> Size -> Bool)
    -> (Size -> Size -> Bool)
    -> (Size -> Size -> Bool)
    -> (Size -> Size -> Bool)
    -> (Size -> Size -> Size)
    -> (Size -> Size -> Size)
    -> Ord Size
    Size -> Size -> Bool
    Size -> Size -> Ordering
    Size -> Size -> Size
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Size -> Size -> Ordering
    compare :: Size -> Size -> Ordering
    $c< :: Size -> Size -> Bool
    < :: Size -> Size -> Bool
    $c<= :: Size -> Size -> Bool
    <= :: Size -> Size -> Bool
    $c> :: Size -> Size -> Bool
    > :: Size -> Size -> Bool
    $c>= :: Size -> Size -> Bool
    >= :: Size -> Size -> Bool
    $cmax :: Size -> Size -> Size
    max :: Size -> Size -> Size
    $cmin :: Size -> Size -> Size
    min :: Size -> Size -> Size
    Ord, Integer -> Size
    Size -> Size
    Size -> Size -> Size
    (Size -> Size -> Size)
    -> (Size -> Size -> Size)
    -> (Size -> Size -> Size)
    -> (Size -> Size)
    -> (Size -> Size)
    -> (Size -> Size)
    -> (Integer -> Size)
    -> Num Size
    forall a.
    (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (Integer -> a)
    -> Num a
    $c+ :: Size -> Size -> Size
    + :: Size -> Size -> Size
    $c- :: Size -> Size -> Size
    - :: Size -> Size -> Size
    $c* :: Size -> Size -> Size
    * :: Size -> Size -> Size
    $cnegate :: Size -> Size
    negate :: Size -> Size
    $cabs :: Size -> Size
    abs :: Size -> Size
    $csignum :: Size -> Size
    signum :: Size -> Size
    $cfromInteger :: Integer -> Size
    fromInteger :: Integer -> Size
    Num, Num Size
    Ord Size
    (Num Size, Ord Size) => (Size -> Rational) -> Real Size
    Size -> Rational
    forall a. (Num a, Ord a) => (a -> Rational) -> Real a
    $ctoRational :: Size -> Rational
    toRational :: Size -> Rational
    Real, Int -> Size
    Size -> Int
    Size -> [Size]
    Size -> Size
    Size -> Size -> [Size]
    Size -> Size -> Size -> [Size]
    (Size -> Size)
    -> (Size -> Size)
    -> (Int -> Size)
    -> (Size -> Int)
    -> (Size -> [Size])
    -> (Size -> Size -> [Size])
    -> (Size -> Size -> [Size])
    -> (Size -> Size -> Size -> [Size])
    -> Enum Size
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    $csucc :: Size -> Size
    succ :: Size -> Size
    $cpred :: Size -> Size
    pred :: Size -> Size
    $ctoEnum :: Int -> Size
    toEnum :: Int -> Size
    $cfromEnum :: Size -> Int
    fromEnum :: Size -> Int
    $cenumFrom :: Size -> [Size]
    enumFrom :: Size -> [Size]
    $cenumFromThen :: Size -> Size -> [Size]
    enumFromThen :: Size -> Size -> [Size]
    $cenumFromTo :: Size -> Size -> [Size]
    enumFromTo :: Size -> Size -> [Size]
    $cenumFromThenTo :: Size -> Size -> Size -> [Size]
    enumFromThenTo :: Size -> Size -> Size -> [Size]
    Enum, Enum Size
    Real Size
    (Real Size, Enum Size) =>
    (Size -> Size -> Size)
    -> (Size -> Size -> Size)
    -> (Size -> Size -> Size)
    -> (Size -> Size -> Size)
    -> (Size -> Size -> (Size, Size))
    -> (Size -> Size -> (Size, Size))
    -> (Size -> Integer)
    -> Integral Size
    Size -> Integer
    Size -> Size -> (Size, Size)
    Size -> Size -> Size
    forall a.
    (Real a, Enum a) =>
    (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> (a, a))
    -> (a -> a -> (a, a))
    -> (a -> Integer)
    -> Integral a
    $cquot :: Size -> Size -> Size
    quot :: Size -> Size -> Size
    $crem :: Size -> Size -> Size
    rem :: Size -> Size -> Size
    $cdiv :: Size -> Size -> Size
    div :: Size -> Size -> Size
    $cmod :: Size -> Size -> Size
    mod :: Size -> Size -> Size
    $cquotRem :: Size -> Size -> (Size, Size)
    quotRem :: Size -> Size -> (Size, Size)
    $cdivMod :: Size -> Size -> (Size, Size)
    divMod :: Size -> Size -> (Size, Size)
    $ctoInteger :: Size -> Integer
    toInteger :: Size -> Integer
    Integral)

    instance Show Size where
      showsPrec :: Int -> Size -> ShowS
    showsPrec Int
    p (Size Int
    x) =
        Bool -> ShowS -> ShowS
    showParen (Int
    p Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    10) (ShowS -> ShowS) -> ShowS -> ShowS
    forall a b. (a -> b) -> a -> b
    $
          String -> ShowS
    showString String
    "Size " ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
          Int -> Int -> ShowS
    forall a. Show a => Int -> a -> ShowS
    showsPrec Int
    11 Int
    x

    instance Read Size where
      readsPrec :: Int -> ReadS Size
    readsPrec Int
    p =
        Bool -> ReadS Size -> ReadS Size
    forall a. Bool -> ReadS a -> ReadS a
    readParen (Int
    p Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    10) (ReadS Size -> ReadS Size) -> ReadS Size -> ReadS Size
    forall a b. (a -> b) -> a -> b
    $ \String
    r0 -> do
          ("Size", r1) <- ReadS String
    lex String
    r0
          (s, r2) <- readsPrec 11 r1
          pure (Size s, r2)

    -- | A range describes the bounds of a number to generate, which may or may not
    --   be dependent on a 'Size'.
    --
    --   The constructor takes an origin between the lower and upper bound, and a
    --   function from 'Size' to bounds.  As the size goes towards @0@, the values
    --   go towards the origin.
    --
    data Range a =
      Range !a (Size -> (a, a))

    instance Functor Range where
      fmap :: forall a b. (a -> b) -> Range a -> Range b
    fmap a -> b
    f (Range a
    z Size -> (a, a)
    g) =
        b -> (Size -> (b, b)) -> Range b
    forall a. a -> (Size -> (a, a)) -> Range a
    Range (a -> b
    f a
    z) ((Size -> (b, b)) -> Range b) -> (Size -> (b, b)) -> Range b
    forall a b. (a -> b) -> a -> b
    $ \Size
    sz ->
          (a -> b) -> (a -> b) -> (a, a) -> (b, b)
    forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
    forall (p :: * -> * -> *) a b c d.
    Bifunctor p =>
    (a -> b) -> (c -> d) -> p a c -> p b d
    bimap a -> b
    f a -> b
    f (Size -> (a, a)
    g Size
    sz)

    -- | Get the origin of a range. This might be the mid-point or the lower bound,
    --   depending on what the range represents.
    --
    --   The 'bounds' of a range are scaled around this value when using the
    --   'linear' family of combinators.
    --
    --   When using a 'Range' to generate numbers, the shrinking function will
    --   shrink towards the origin.
    --
    origin :: Range a -> a
    origin :: forall a. Range a -> a
    origin (Range a
    z Size -> (a, a)
    _) =
      a
    z

    -- | Get the extents of a range, for a given size.
    --
    bounds :: Size -> Range a -> (a, a)
    bounds :: forall a. Size -> Range a -> (a, a)
    bounds Size
    sz (Range a
    _ Size -> (a, a)
    f) =
      Size -> (a, a)
    f Size
    sz

    -- | Get the lower bound of a range for the given size.
    --
    lowerBound :: Ord a => Size -> Range a -> a
    lowerBound :: forall a. Ord a => Size -> Range a -> a
    lowerBound Size
    sz Range a
    range =
      let
        (a
    x, a
    y) =
          Size -> Range a -> (a, a)
    forall a. Size -> Range a -> (a, a)
    bounds Size
    sz Range a
    range
      in
        a -> a -> a
    forall a. Ord a => a -> a -> a
    min a
    x a
    y

    -- | Get the upper bound of a range for the given size.
    --
    upperBound :: Ord a => Size -> Range a -> a
    upperBound :: forall a. Ord a => Size -> Range a -> a
    upperBound Size
    sz Range a
    range =
      let
        (a
    x, a
    y) =
          Size -> Range a -> (a, a)
    forall a. Size -> Range a -> (a, a)
    bounds Size
    sz Range a
    range
      in
        a -> a -> a
    forall a. Ord a => a -> a -> a
    max a
    x a
    y

    -- | Construct a range which represents a constant single value.
    --
    --   >>> bounds x $ singleton 5
    --   (5,5)
    --
    --   >>> origin $ singleton 5
    --   5
    --
    singleton :: a -> Range a
    singleton :: forall a. a -> Range a
    singleton a
    x =
      a -> (Size -> (a, a)) -> Range a
    forall a. a -> (Size -> (a, a)) -> Range a
    Range a
    x ((Size -> (a, a)) -> Range a) -> (Size -> (a, a)) -> Range a
    forall a b. (a -> b) -> a -> b
    $ \Size
    _ -> (a
    x, a
    x)

    -- | Construct a range which is unaffected by the size parameter.
    --
    --   A range from @0@ to @10@, with the origin at @0@:
    --
    --   >>> bounds x $ constant 0 10
    --   (0,10)
    --
    --   >>> origin $ constant 0 10
    --   0
    --
    constant :: a -> a -> Range a
    constant :: forall a. a -> a -> Range a
    constant a
    x a
    y =
      a -> a -> a -> Range a
    forall a. a -> a -> a -> Range a
    constantFrom a
    x a
    x a
    y

    -- | Construct a range which is unaffected by the size parameter with a origin
    --   point which may differ from the bounds.
    --
    --   A range from @-10@ to @10@, with the origin at @0@:
    --
    --   >>> bounds x $ constantFrom 0 (-10) 10
    --   (-10,10)
    --
    --   >>> origin $ constantFrom 0 (-10) 10
    --   0
    --
    --   A range from @1970@ to @2100@, with the origin at @2000@:
    --
    --   >>> bounds x $ constantFrom 2000 1970 2100
    --   (1970,2100)
    --
    --   >>> origin $ constantFrom 2000 1970 2100
    --   2000
    --
    constantFrom ::
         a -- ^ Origin (the value produced when the size parameter is 0).
      -> a -- ^ Lower bound (the bottom of the range when the size parameter is 99).
      -> a -- ^ Upper bound (the top of the range when the size parameter is 99).
      -> Range a
    constantFrom :: forall a. a -> a -> a -> Range a
    constantFrom a
    z a
    x a
    y =
      a -> (Size -> (a, a)) -> Range a
    forall a. a -> (Size -> (a, a)) -> Range a
    Range a
    z ((Size -> (a, a)) -> Range a) -> (Size -> (a, a)) -> Range a
    forall a b. (a -> b) -> a -> b
    $ \Size
    _ -> (a
    x, a
    y)

    -- | Construct a range which is unaffected by the size parameter using the full
    --   range of a data type.
    --
    --   A range from @-128@ to @127@, with the origin at @0@:
    --
    --   >>> bounds x (constantBounded :: Range Int8)
    --   (-128,127)
    --
    --   >>> origin (constantBounded :: Range Int8)
    --   0
    --
    constantBounded :: (Bounded a, Num a) => Range a
    constantBounded :: forall a. (Bounded a, Num a) => Range a
    constantBounded =
      a -> a -> a -> Range a
    forall a. a -> a -> a -> Range a
    constantFrom a
    0 a
    forall a. Bounded a => a
    minBound a
    forall a. Bounded a => a
    maxBound

    -- | Construct a range which scales the second bound relative to the size
    --   parameter.
    --
    --   >>> bounds 0 $ linear 0 10
    --   (0,0)
    --
    --   >>> bounds 50 $ linear 0 10
    --   (0,5)
    --
    --   >>> bounds 99 $ linear 0 10
    --   (0,10)
    --
    linear :: Integral a => a -> a -> Range a
    linear :: forall a. Integral a => a -> a -> Range a
    linear a
    x a
    y =
      a -> a -> a -> Range a
    forall a. Integral a => a -> a -> a -> Range a
    linearFrom a
    x a
    x a
    y

    -- | Construct a range which scales the bounds relative to the size parameter.
    --
    --   >>> bounds 0 $ linearFrom 0 (-10) 10
    --   (0,0)
    --
    --   >>> bounds 50 $ linearFrom 0 (-10) 20
    --   (-5,10)
    --
    --   >>> bounds 99 $ linearFrom 0 (-10) 20
    --   (-10,20)
    --
    linearFrom :: Integral a
      => a -- ^ Origin (the value produced when the size parameter is 0).
      -> a -- ^ Lower bound (the bottom of the range when the size parameter is 99).
      -> a -- ^ Upper bound (the top of the range when the size parameter is 99).
      -> Range a
    linearFrom :: forall a. Integral a => a -> a -> a -> Range a
    linearFrom a
    z a
    x a
    y =
      a -> (Size -> (a, a)) -> Range a
    forall a. a -> (Size -> (a, a)) -> Range a
    Range a
    z ((Size -> (a, a)) -> Range a) -> (Size -> (a, a)) -> Range a
    forall a b. (a -> b) -> a -> b
    $ \Size
    sz ->
        let
          x_sized :: a
    x_sized =
            a -> a -> a -> a
    forall a. Ord a => a -> a -> a -> a
    clamp a
    x a
    y (a -> a) -> a -> a
    forall a b. (a -> b) -> a -> b
    $ Size -> a -> a -> a
    forall a. Integral a => Size -> a -> a -> a
    scaleLinear Size
    sz a
    z a
    x

          y_sized :: a
    y_sized =
            a -> a -> a -> a
    forall a. Ord a => a -> a -> a -> a
    clamp a
    x a
    y (a -> a) -> a -> a
    forall a b. (a -> b) -> a -> b
    $ Size -> a -> a -> a
    forall a. Integral a => Size -> a -> a -> a
    scaleLinear Size
    sz a
    z a
    y
        in
          (a
    x_sized, a
    y_sized)

    -- | Construct a range which is scaled relative to the size parameter and uses
    --   the full range of a data type.
    --
    --   >>> bounds 0 (linearBounded :: Range Int8)
    --   (0,0)
    --
    --   >>> bounds 50 (linearBounded :: Range Int8)
    --   (-64,64)
    --
    --   >>> bounds 99 (linearBounded :: Range Int8)
    --   (-128,127)
    --
    linearBounded :: (Bounded a, Integral a) => Range a
    linearBounded :: forall a. (Bounded a, Integral a) => Range a
    linearBounded =
      a -> a -> a -> Range a
    forall a. Integral a => a -> a -> a -> Range a
    linearFrom a
    0 a
    forall a. Bounded a => a
    minBound a
    forall a. Bounded a => a
    maxBound

    -- | Construct a range which scales the second bound relative to the size
    --   parameter.
    --
    --   /This works the same as 'linear', but for fractional values./
    --
    linearFrac :: (Fractional a, Ord a) => a -> a -> Range a
    linearFrac :: forall a. (Fractional a, Ord a) => a -> a -> Range a
    linearFrac a
    x a
    y =
      a -> a -> a -> Range a
    forall a. (Fractional a, Ord a) => a -> a -> a -> Range a
    linearFracFrom a
    x a
    x a
    y

    -- | Construct a range which scales the bounds relative to the size parameter.
    --
    --   /This works the same as 'linearFrom', but for fractional values./
    --
    linearFracFrom :: (Fractional a, Ord a) => a -> a -> a -> Range a
    linearFracFrom :: forall a. (Fractional a, Ord a) => a -> a -> a -> Range a
    linearFracFrom a
    z a
    x a
    y =
      a -> (Size -> (a, a)) -> Range a
    forall a. a -> (Size -> (a, a)) -> Range a
    Range a
    z ((Size -> (a, a)) -> Range a) -> (Size -> (a, a)) -> Range a
    forall a b. (a -> b) -> a -> b
    $ \Size
    sz ->
        let
          x_sized :: a
    x_sized =
            a -> a -> a -> a
    forall a. Ord a => a -> a -> a -> a
    clamp a
    x a
    y (a -> a) -> a -> a
    forall a b. (a -> b) -> a -> b
    $ Size -> a -> a -> a
    forall a. Fractional a => Size -> a -> a -> a
    scaleLinearFrac Size
    sz a
    z a
    x

          y_sized :: a
    y_sized =
            a -> a -> a -> a
    forall a. Ord a => a -> a -> a -> a
    clamp a
    x a
    y (a -> a) -> a -> a
    forall a b. (a -> b) -> a -> b
    $ Size -> a -> a -> a
    forall a. Fractional a => Size -> a -> a -> a
    scaleLinearFrac Size
    sz a
    z a
    y
        in
          (a
    x_sized, a
    y_sized)

    -- | Truncate a value so it stays within some range.
    --
    --   >>> clamp 5 10 15
    --   10
    --
    --   >>> clamp 5 10 0
    --   5
    --
    clamp :: Ord a => a -> a -> a -> a
    clamp :: forall a. Ord a => a -> a -> a -> a
    clamp a
    x a
    y a
    n =
      if a
    x a -> a -> Bool
    forall a. Ord a => a -> a -> Bool
    > a
    y then
        a -> a -> a
    forall a. Ord a => a -> a -> a
    min a
    x (a -> a -> a
    forall a. Ord a => a -> a -> a
    max a
    y a
    n)
      else
        a -> a -> a
    forall a. Ord a => a -> a -> a
    min a
    y (a -> a -> a
    forall a. Ord a => a -> a -> a
    max a
    x a
    n)

    -- | Scale an integral linearly with the size parameter.
    --
    scaleLinear :: Integral a => Size -> a -> a -> a
    scaleLinear :: forall a. Integral a => Size -> a -> a -> a
    scaleLinear Size
    sz0 a
    z0 a
    n0 =
      let
        sz :: Size
    sz =
          Size -> Size -> Size
    forall a. Ord a => a -> a -> a
    max Size
    0 (Size -> Size -> Size
    forall a. Ord a => a -> a -> a
    min Size
    99 Size
    sz0)

        z :: Integer
    z =
          a -> Integer
    forall a. Integral a => a -> Integer
    toInteger a
    z0

        n :: Integer
    n =
          a -> Integer
    forall a. Integral a => a -> Integer
    toInteger a
    n0

        -- @rng@ has magnitude 1 bigger than the biggest diff
        -- i.e. it specifies the range the diff can be in [0,rng)
        -- with the upper bound being exclusive.
        rng :: Integer
    rng =
          Integer
    n Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    z Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    + Integer -> Integer
    forall a. Num a => a -> a
    signum (Integer
    n Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    z)

        diff :: Integer
    diff =
          (Integer
    rng Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * Size -> Integer
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Size
    sz) Integer -> Integer -> Integer
    forall a. Integral a => a -> a -> a
    `quot` Integer
    100
      in
        Integer -> a
    forall a. Num a => Integer -> a
    fromInteger (Integer -> a) -> Integer -> a
    forall a b. (a -> b) -> a -> b
    $ Integer
    z Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    + Integer
    diff

    -- | Scale a fractional number linearly with the size parameter.
    --
    scaleLinearFrac :: Fractional a => Size -> a -> a -> a
    scaleLinearFrac :: forall a. Fractional a => Size -> a -> a -> a
    scaleLinearFrac Size
    sz0 a
    z a
    n =
      let
        sz :: Size
    sz =
          Size -> Size -> Size
    forall a. Ord a => a -> a -> a
    max Size
    0 (Size -> Size -> Size
    forall a. Ord a => a -> a -> a
    min Size
    99 Size
    sz0)

        diff :: a
    diff =
          (a
    n a -> a -> a
    forall a. Num a => a -> a -> a
    - a
    z) a -> a -> a
    forall a. Num a => a -> a -> a
    * (Size -> a
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Size
    sz a -> a -> a
    forall a. Fractional a => a -> a -> a
    / a
    99)
      in
        a
    z a -> a -> a
    forall a. Num a => a -> a -> a
    + a
    diff

    -- | Construct a range which scales the second bound exponentially relative to
    --   the size parameter.
    --
    --   >>> bounds 0 $ exponential 1 512
    --   (1,1)
    --
    --   >>> bounds 11 $ exponential 1 512
    --   (1,2)
    --
    --   >>> bounds 22 $ exponential 1 512
    --   (1,4)
    --
    --   >>> bounds 77 $ exponential 1 512
    --   (1,128)
    --
    --   >>> bounds 88 $ exponential 1 512
    --   (1,256)
    --
    --   >>> bounds 99 $ exponential 1 512
    --   (1,512)
    --
    exponential :: Integral a => a -> a -> Range a
    exponential :: forall a. Integral a => a -> a -> Range a
    exponential a
    x a
    y =
      a -> a -> a -> Range a
    forall a. Integral a => a -> a -> a -> Range a
    exponentialFrom a
    x a
    x a
    y

    -- | Construct a range which scales the bounds exponentially relative to the
    -- size parameter.
    --
    --   >>> bounds 0 $ exponentialFrom 0 (-128) 512
    --   (0,0)
    --
    --   >>> bounds 25 $ exponentialFrom 0 (-128) 512
    --   (-2,4)
    --
    --   >>> bounds 50 $ exponentialFrom 0 (-128) 512
    --   (-11,22)
    --
    --   >>> bounds 75 $ exponentialFrom 0 (-128) 512
    --   (-39,112)
    --
    --   >>> bounds 99 $ exponentialFrom x (-128) 512
    --   (-128,512)
    --
    exponentialFrom :: Integral a
      => a -- ^ Origin (the value produced when the size parameter is 0).
      -> a -- ^ Lower bound (the bottom of the range when the size parameter is 99).
      -> a -- ^ Upper bound (the top of the range when the size parameter is 99).
      -> Range a
    exponentialFrom :: forall a. Integral a => a -> a -> a -> Range a
    exponentialFrom a
    z a
    x a
    y =
      a -> (Size -> (a, a)) -> Range a
    forall a. a -> (Size -> (a, a)) -> Range a
    Range a
    z ((Size -> (a, a)) -> Range a) -> (Size -> (a, a)) -> Range a
    forall a b. (a -> b) -> a -> b
    $ \Size
    sz ->
        let
          sized_x :: a
    sized_x =
            a -> a -> a -> a
    forall a. Ord a => a -> a -> a -> a
    clamp a
    x a
    y (a -> a) -> a -> a
    forall a b. (a -> b) -> a -> b
    $ Size -> a -> a -> a
    forall a. Integral a => Size -> a -> a -> a
    scaleExponential Size
    sz a
    z a
    x

          sized_y :: a
    sized_y =
            a -> a -> a -> a
    forall a. Ord a => a -> a -> a -> a
    clamp a
    x a
    y (a -> a) -> a -> a
    forall a b. (a -> b) -> a -> b
    $ Size -> a -> a -> a
    forall a. Integral a => Size -> a -> a -> a
    scaleExponential Size
    sz a
    z a
    y
        in
          (a
    sized_x, a
    sized_y)

    -- | Construct a range which is scaled exponentially relative to the size
    --   parameter and uses the full range of a data type.
    --
    --   >>> bounds 0 (exponentialBounded :: Range Int8)
    --   (0,0)
    --
    --   >>> bounds 50 (exponentialBounded :: Range Int8)
    --   (-11,11)
    --
    --   >>> bounds 99 (exponentialBounded :: Range Int8)
    --   (-128,127)
    --
    exponentialBounded :: (Bounded a, Integral a) => Range a
    exponentialBounded :: forall a. (Bounded a, Integral a) => Range a
    exponentialBounded =
      a -> a -> a -> Range a
    forall a. Integral a => a -> a -> a -> Range a
    exponentialFrom a
    0 a
    forall a. Bounded a => a
    minBound a
    forall a. Bounded a => a
    maxBound

    -- | Construct a range which scales the second bound exponentially relative to
    --   the size parameter.
    --
    --   /This works the same as 'exponential', but for floating-point values./
    --
    --   >>> bounds 0 $ exponentialFloat 0 10
    --   (0.0,0.0)
    --
    --   >>> bounds 50 $ exponentialFloat 0 10
    --   (0.0,2.357035250656098)
    --
    --   >>> bounds 99 $ exponentialFloat 0 10
    --   (0.0,10.0)
    --
    exponentialFloat :: (Floating a, Ord a) => a -> a -> Range a
    exponentialFloat :: forall a. (Floating a, Ord a) => a -> a -> Range a
    exponentialFloat a
    x a
    y =
      a -> a -> a -> Range a
    forall a. (Floating a, Ord a) => a -> a -> a -> Range a
    exponentialFloatFrom a
    x a
    x a
    y

    -- | Construct a range which scales the bounds exponentially relative to the
    --   size parameter.
    --
    --   /This works the same as 'exponentialFrom', but for floating-point values./
    --
    --   >>> bounds 0 $ exponentialFloatFrom 0 (-10) 20
    --   (0.0,0.0)
    --
    --   >>> bounds 50 $ exponentialFloatFrom 0 (-10) 20
    --   (-2.357035250656098,3.6535836249197002)
    --
    --   >>> bounds 99 $ exponentialFloatFrom x (-10) 20
    --   (-10.0,20.0)
    --
    exponentialFloatFrom :: (Floating a, Ord a) => a -> a -> a -> Range a
    exponentialFloatFrom :: forall a. (Floating a, Ord a) => a -> a -> a -> Range a
    exponentialFloatFrom a
    z a
    x a
    y =
      a -> (Size -> (a, a)) -> Range a
    forall a. a -> (Size -> (a, a)) -> Range a
    Range a
    z ((Size -> (a, a)) -> Range a) -> (Size -> (a, a)) -> Range a
    forall a b. (a -> b) -> a -> b
    $ \Size
    sz ->
        let
          sized_x :: a
    sized_x =
            a -> a -> a -> a
    forall a. Ord a => a -> a -> a -> a
    clamp a
    x a
    y (a -> a) -> a -> a
    forall a b. (a -> b) -> a -> b
    $ Size -> a -> a -> a
    forall a. Floating a => Size -> a -> a -> a
    scaleExponentialFloat Size
    sz a
    z a
    x

          sized_y :: a
    sized_y =
            a -> a -> a -> a
    forall a. Ord a => a -> a -> a -> a
    clamp a
    x a
    y (a -> a) -> a -> a
    forall a b. (a -> b) -> a -> b
    $ Size -> a -> a -> a
    forall a. Floating a => Size -> a -> a -> a
    scaleExponentialFloat Size
    sz a
    z a
    y
        in
          (a
    sized_x, a
    sized_y)

    -- | Scale an integral exponentially with the size parameter.
    --
    scaleExponential :: Integral a => Size -> a -> a -> a
    scaleExponential :: forall a. Integral a => Size -> a -> a -> a
    scaleExponential Size
    sz a
    z0 a
    n0 =
      let
        z :: Double
    z =
          a -> Double
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral a
    z0

        n :: Double
    n =
          a -> Double
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral a
    n0
      in
        Double -> a
    forall b. Integral b => Double -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    round (Size -> Double -> Double -> Double
    forall a. Floating a => Size -> a -> a -> a
    scaleExponentialFloat Size
    sz Double
    z Double
    n :: Double)

    -- | Scale a floating-point number exponentially with the size parameter.
    --
    scaleExponentialFloat :: Floating a => Size -> a -> a -> a
    scaleExponentialFloat :: forall a. Floating a => Size -> a -> a -> a
    scaleExponentialFloat Size
    sz0 a
    z a
    n =
      let
        sz :: Size
    sz =
          Size -> Size -> Size -> Size
    forall a. Ord a => a -> a -> a -> a
    clamp Size
    0 Size
    99 Size
    sz0

        diff :: a
    diff =
          (((a -> a
    forall a. Num a => a -> a
    abs (a
    n a -> a -> a
    forall a. Num a => a -> a -> a
    - a
    z) a -> a -> a
    forall a. Num a => a -> a -> a
    + a
    1) a -> a -> a
    forall a. Floating a => a -> a -> a
    ** (Size -> a
    forall a b. (Real a, Fractional b) => a -> b
    realToFrac Size
    sz a -> a -> a
    forall a. Fractional a => a -> a -> a
    / a
    99)) a -> a -> a
    forall a. Num a => a -> a -> a
    - a
    1) a -> a -> a
    forall a. Num a => a -> a -> a
    * a -> a
    forall a. Num a => a -> a
    signum (a
    n a -> a -> a
    forall a. Num a => a -> a -> a
    - a
    z)
      in
        a
    z a -> a -> a
    forall a. Num a => a -> a -> a
    + a
    diff

    ------------------------------------------------------------------------
    -- Internal

    -- $internal
    --
    -- These functions are exported in case you need them in a pinch, but are not
    -- part of the public API and may change at any time, even as part of a minor
    -- update.