{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE Safe #-}
#ifndef MIN_VERSION_transformers
#define MIN_VERSION_transformers(x,y,z) 0
#endif
#ifndef MIN_VERSION_transformers_compat
#define MIN_VERSION_transformers_compat(x,y,z) 0
#endif
#if MIN_VERSION_base(4,9,0)
#define LIFTED_FUNCTOR_CLASSES 1
#elif MIN_VERSION_transformers(0,5,0)
#define LIFTED_FUNCTOR_CLASSES 1
#elif MIN_VERSION_transformers_compat(0,5,0) && !MIN_VERSION_transformers(0,4,0)
#define LIFTED_FUNCTOR_CLASSES 1
#endif
module Data.Function.Step.Discrete.Closed (
SF (..),
constant,
step,
fromList,
normalise,
(!),
values,
toDense,
fromDense,
showSF,
putSF,
) where
import Control.Applicative (liftA2)
import Control.DeepSeq (NFData (..))
import Control.Monad (ap)
import Data.Maybe (mapMaybe)
import Data.Functor.Classes
import Data.List (intercalate)
import Data.Map (Map)
import Prelude ()
import Prelude.Compat
#ifdef LIFTED_FUNCTOR_CLASSES
import Text.Show (showListWith)
#endif
import qualified Data.Function.Step as SF
import qualified Data.Map as Map
import qualified Test.QuickCheck as QC
data SF k v = SF !(Map k v) !v
deriving (Eq, Ord, Functor, Foldable, Traversable)
instance Ord k => Applicative (SF k) where
pure = constant
(<*>) = ap
instance Ord k => Monad (SF k) where
return = pure
SF m def0 >>= f = SF
(Map.fromDistinctAscList $ mkDistinctAscList $ pieces ++ pieces1)
def1
where
pieces =
[ (min k k', v')
| (k, v) <- Map.toList m
, let SF m' def = f v
, (k', v') <- Map.toList m' ++ [(k, def)]
]
(pieces1, def1) = let SF m' def = f def0 in (Map.toList m', def)
instance (Ord k, Semigroup v) => Semigroup (SF k v) where
(<>) = liftA2 (<>)
instance (Ord k, Monoid v) => Monoid (SF k v) where
mempty = pure mempty
mappend = liftA2 mappend
instance (Ord k, QC.Arbitrary k, QC.Arbitrary v) => QC.Arbitrary (SF k v) where
arbitrary = fromList <$> QC.arbitrary <*> QC.arbitrary
shrink (SF m v) = uncurry fromList <$> QC.shrink (Map.toList m, v)
instance (NFData k, NFData v) => NFData (SF k v) where
rnf (SF m v) = rnf (m, v)
#if LIFTED_FUNCTOR_CLASSES
instance Show2 SF where
liftShowsPrec2 spk slk spv slv d (SF m v) = showsBinaryWith
(\_ -> showListWith $ liftShowsPrec2 spk slk spv slv 0)
spv
"fromList" d (Map.toList m) v
instance Show k => Show1 (SF k) where
liftShowsPrec = liftShowsPrec2 showsPrec showList
instance (Show k, Show v) => Show (SF k v) where
showsPrec = showsPrec2
#else
instance (Show k, Show v) => Show (SF k v) where
showsPrec d (SF m v) = showParen (d > 10)
$ showString "fromList"
. showsPrec 11 (Map.toList m)
. showChar ' '
. showsPrec 11 v
instance Show k => Show1 (SF k) where showsPrec1 = showsPrec
#endif
mkDistinctAscList :: Ord k => [(k, b)] -> [(k, b)]
mkDistinctAscList [] = []
mkDistinctAscList ((k, v) : kv) = (k, v) : mkDistinctAscList' k kv
mkDistinctAscList' :: Ord k => k -> [(k, b)] -> [(k, b)]
mkDistinctAscList' _ [] = []
mkDistinctAscList' k (p@(k', _) : kv)
| k < k' = p : mkDistinctAscList' k' kv
| otherwise = mkDistinctAscList' k kv
infixl 9 !
(!) :: Ord k => SF k v -> k -> v
SF m def ! x = case Map.lookupGE x m of
Nothing -> def
Just (_, v) -> v
constant :: a -> SF k a
constant = SF Map.empty
step :: k -> v -> v -> SF k v
step k = SF . Map.singleton k
fromList :: Ord k => [(k, v)] -> v -> SF k v
fromList = SF . Map.fromList
values :: SF k v -> [v]
values (SF m v) = Map.elems m ++ [v]
normalise :: Eq v => SF k v -> SF k v
normalise (SF m v) = uncurry mk $ foldr go ([], v) (Map.toList m) where
mk m' _ = SF (Map.fromDistinctAscList m') v
go p@(_, v') p'@(m', x)
| v' == x = p'
| otherwise = (p : m', v')
toDense :: SF a b -> SF.SF a b
toDense (SF m v) = SF.SF (Map.mapKeysMonotonic SF.Closed m) v
fromDense
:: Ord a
=> (a -> Maybe a)
-> SF.SF a b
-> SF a b
fromDense prev (SF.SF m v) = SF (mapKeys m) v where
mapKeys = Map.fromListWith (\_ -> id) . mapMaybe (_1 fk) . Map.toList
fk (SF.Open k) = prev k
fk (SF.Closed k) = Just k
_1 :: Functor f => (a -> f b) -> (a, c) -> f (b, c)
_1 f (a, c) = fmap (\b -> (b, c)) (f a)
showSF :: (Show a, Show b) => SF a b -> String
showSF (SF m v) | Map.null m = "\\_ -> " ++ show v
showSF (SF m v) = intercalate "\n" $
"\\x -> if" : [ " | " ++ leftPad k ++ " -> " ++ x | (k, x) <- cases ]
where
cases = [ ("x <= " ++ showsPrec 5 k "", show x) | (k,x) <- Map.toList m ] ++
[ ("otherwise", show v) ]
len = maximum (map (length . fst) cases)
leftPad s = s ++ replicate (len - length s) ' '
putSF :: (Show a, Show b) => SF a b -> IO ()
putSF = putStrLn . showSF