I was able to implement an arbitrary monotonic function like this:
-- | A modifier to generate monotonic functions
newtype Monotonic a b = Monotonic (a -> b)
instance Show (Monotonic a b) where
show _ = "<monotonic fun>"
instance (Show b, Real a, Arbitrary b, Fractional b, Real b, Ord b) => Arbitrary (Monotonic a b) where
arbitrary = do
x <- arbitrary
ups <- infiniteListMonotonic
downs <- infiniteListMonotonic
pure $ Monotonic $ \a ->
let (n, frac) = properFraction $ toRational a
(getIndex, index) =
if n >= 0
then (\i -> x + (ups !! i), n)
else (\i -> x - (downs !! i), (-n))
lo = getIndex index
hi = getIndex (index + 1)
in lo + fromRational frac * (hi - lo)
where
infiniteListMonotonic = scanl1 (+) . map getNonNegative <$> infiniteList
It would be great if this could be included in the base library, potentially with extra features like:
Shrinking, the same way Fun does
Make a new type class to support outputs that are integral or non-numerical
e.g. for Double -> Int, interpolate between the two ints, then round or truncate
Make a new type class to support inputs that are still orderable, but non-numerical
I was able to implement an arbitrary monotonic function like this:
It would be great if this could be included in the base library, potentially with extra features like:
Fun
doesDouble -> Int
, interpolate between the two ints, thenround
ortruncate
Make a new type class to support inputs that are still orderable, but non-numerical
arbitrary :: Gen (Octal -> Int)