-- | Generated functions
--
-- Intended for unqualified import.
module Test.Falsify.Internal.Fun (
    Fun(..)
    -- * Patterns
  , applyFun
  , applyFun2
  , applyFun3
  , pattern Fn
  , pattern Fn2
  , pattern Fn3
  ) where

import Data.Falsify.ConcreteFun ((:->)(..))
import qualified Data.Falsify.ConcreteFun as ConcreteFun

{-------------------------------------------------------------------------------
  Definition
-------------------------------------------------------------------------------}

-- | Function @a -> b@ which can be shown, generated, and shrunk
data Fun a b = Fun {
      forall a b. Fun a b -> a :-> b
concrete      :: a :-> b
    , forall a b. Fun a b -> b
defaultValue  :: b

      -- Since functions are typically infinite, they can only safely be shown
      -- once they are fully shrunk: after all, once a function has been fully
      -- shrunk, we /know/ it must be finite, because in any given property, a
      -- function will only ever be applied a finite number of times.
    , forall a b. Fun a b -> Bool
isFullyShrunk :: Bool
    }
  deriving ((forall a b. (a -> b) -> Fun a a -> Fun a b)
-> (forall a b. a -> Fun a b -> Fun a a) -> Functor (Fun a)
forall a b. a -> Fun a b -> Fun a a
forall a b. (a -> b) -> Fun a a -> Fun a b
forall a a b. a -> Fun a b -> Fun a a
forall a a b. (a -> b) -> Fun a a -> Fun a b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a a b. (a -> b) -> Fun a a -> Fun a b
fmap :: forall a b. (a -> b) -> Fun a a -> Fun a b
$c<$ :: forall a a b. a -> Fun a b -> Fun a a
<$ :: forall a b. a -> Fun a b -> Fun a a
Functor)

{-------------------------------------------------------------------------------
  Show functions
-------------------------------------------------------------------------------}

instance (Show a, Show b) => Show (Fun a b) where
  show :: Fun a b -> String
show Fun{a :-> b
concrete :: forall a b. Fun a b -> a :-> b
concrete :: a :-> b
concrete, b
defaultValue :: forall a b. Fun a b -> b
defaultValue :: b
defaultValue, Bool
isFullyShrunk :: forall a b. Fun a b -> Bool
isFullyShrunk :: Bool
isFullyShrunk}
    | Bool
isFullyShrunk = (a :-> b) -> b -> String
forall a b. (Show a, Show b) => (a :-> b) -> b -> String
ConcreteFun.render a :-> b
concrete b
defaultValue
    | Bool
otherwise     = String
"<fun>"

{-------------------------------------------------------------------------------
  Patterns

  These are analogue to their counterparts in QuickCheck.
-------------------------------------------------------------------------------}

-- | Apply function to argument
--
-- See also the 'Fn', 'Fn2', and 'Fn3' patter synonyms.
applyFun :: Fun a b -> a -> b
applyFun :: forall a b. Fun a b -> a -> b
applyFun Fun{a :-> b
concrete :: forall a b. Fun a b -> a :-> b
concrete :: a :-> b
concrete, b
defaultValue :: forall a b. Fun a b -> b
defaultValue :: b
defaultValue} = (a :-> b) -> b -> a -> b
forall a b. (a :-> b) -> b -> a -> b
ConcreteFun.apply a :-> b
concrete b
defaultValue

-- | Like 'applyFun', but for binary functions
applyFun2 :: Fun (a, b) c -> (a -> b -> c)
applyFun2 :: forall a b c. Fun (a, b) c -> a -> b -> c
applyFun2 Fun (a, b) c
f a
a b
b = Fun (a, b) c -> (a, b) -> c
forall a b. Fun a b -> a -> b
applyFun Fun (a, b) c
f (a
a, b
b)

-- | Like 'applyFun', but for ternary functions
applyFun3 :: Fun (a, b, c) d -> (a -> b -> c -> d)
applyFun3 :: forall a b c d. Fun (a, b, c) d -> a -> b -> c -> d
applyFun3 Fun (a, b, c) d
f a
a b
b c
c = Fun (a, b, c) d -> (a, b, c) -> d
forall a b. Fun a b -> a -> b
applyFun Fun (a, b, c) d
f (a
a, b
b, c
c)

-- | Pattern synonym useful when generating functions of one argument
pattern Fn :: (a -> b) -> Fun a b
pattern $mFn :: forall {r} {a} {b}. Fun a b -> ((a -> b) -> r) -> ((# #) -> r) -> r
Fn f <- (applyFun -> f)

-- | Pattern synonym useful when generating functions of two arguments
pattern Fn2 :: (a -> b -> c) -> Fun (a, b) c
pattern $mFn2 :: forall {r} {a} {b} {c}.
Fun (a, b) c -> ((a -> b -> c) -> r) -> ((# #) -> r) -> r
Fn2 f <- (applyFun2 -> f)

-- | Pattern synonym useful when generating functions of three arguments
pattern Fn3 :: (a -> b -> c -> d) -> Fun (a, b, c) d
pattern $mFn3 :: forall {r} {a} {b} {c} {d}.
Fun (a, b, c) d -> ((a -> b -> c -> d) -> r) -> ((# #) -> r) -> r
Fn3 f <- (applyFun3 -> f)

{-# COMPLETE Fn  #-}
{-# COMPLETE Fn2 #-}
{-# COMPLETE Fn3 #-}