{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE ScopedTypeVariables #-} module Func where import Data.IntMap.Strict (IntMap) import qualified Data.IntMap.Strict as IntMap import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Data.Semiring import Test.QuickCheck import Data.Function import Data.Monoid import CompUtils data Func a b = Func { def :: b , vals :: IntMap b } deriving (Eq,Ord) (#$) :: Enum a => Func a b -> a -> b (#$) f x = IntMap.findWithDefault (def f) (fromEnum x) (vals f) instance (Enum a, Show a, Show b) => Show (Func a b) where showsPrec _ (Func c xs :: Func a b) = showChar '{' . IntMap.foldrWithKey f b xs where f x y a = shows (toEnum x :: a) . showString " -> " . shows y . showString ", " . a b = showString "_ -> " . shows c . showChar '}' fromFunc :: (Enum a, Bounded a, Ord b) => (a -> b) -> Func a b fromFunc f = uncurry Func . fmap IntMap.fromList . remMostFreq $ [ (fromEnum x, f x) | x <- [minBound .. maxBound] ] where remMostFreq xs = (mf, filter ((mf/=) . snd) xs) where Just mf = mostFrequent (map snd xs) mostFrequent :: Ord a => [a] -> Maybe a mostFrequent xs = foldr f (const . fmap fst) xs Nothing (Map.empty :: Map a Int) where f e a Nothing _ = a (Just (e, 1)) (Map.singleton e 1) f e a (Just (b,n)) m | d > n = a (Just (e,d)) nm | otherwise = a (Just (b,n)) nm where (nv,nm) = Map.insertLookupWithKey (const (+)) e 1 m d = maybe 1 succ nv instance (Enum a, Bounded a, Ord b, Semiring b) => Semiring (Func a b) where zero = fromFunc zero one = fromFunc one (<+>) = fromFunc .: (<+>) `on` (#$) (<.>) = fromFunc .: (<.>) `on` (#$) instance (Bounded a, Enum a, Ord b, Arbitrary b, CoArbitrary a) => Arbitrary (Func a b) where arbitrary = fmap fromFunc arbitrary shrink f = fmap fromFunc (shrink (f #$)) newtype EndoFunc a = EndoFunc { getEndoFunc :: Endo a } deriving (Semiring,DetectableZero) instance (Enum a, Bounded a, Ord a) => Eq (EndoFunc a) where (==) = (==) `on` (fromFunc .# appEndo .# getEndoFunc) instance (Enum a, Bounded a, Ord a, Show a) => Show (EndoFunc a) where showsPrec n = showsPrec n . fromFunc .# appEndo .# getEndoFunc instance (Arbitrary a, CoArbitrary a) => Arbitrary (EndoFunc a) where arbitrary = (EndoFunc . Endo) <#$> arbitrary shrink (EndoFunc (Endo f)) = (EndoFunc . Endo) <#$> shrink f