{-# LANGUAGE CPP #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE StandaloneDeriving #-}
#if !MIN_VERSION_base(4,9,0)
{-# OPTIONS_GHC -fno-warn-orphans #-}
#endif
module Data.Semiring.Free
(
#if defined(VERSION_containers)
#if MIN_VERSION_base(4,8,0)
Free(..)
, runFree
, lowerFree
, liftFree
#endif
#endif
) where
#if defined(VERSION_containers)
#if MIN_VERSION_base(4,8,0)
import Control.Applicative (pure)
import Data.Bool (otherwise)
import Data.Coerce (Coercible, coerce)
import Data.Eq (Eq)
import Data.Functor (Functor(..))
import Data.Functor.Identity (Identity(..))
import Data.Function (flip,id, (.))
import Data.Ord (Ord)
#if !MIN_VERSION_base(4,9,0)
import Data.Semigroup ()
#endif
import Data.Semiring
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Monoid (Monoid(..))
import GHC.Show (Show)
import GHC.Read (Read)
import GHC.Real (even, div)
import Numeric.Natural
newtype Free a = Free
{ getFree :: Map (Identity a) Natural
} deriving (Show, Read, Eq, Ord, Semiring)
#if !MIN_VERSION_base(4,9,0)
deriving instance Monoid a => Monoid (Identity a)
#endif
runFree :: Semiring s => (a -> s) -> Free a -> s
runFree f = getAdd #. Map.foldMapWithKey ((rep .# Add) . product . fmap f) . getFree
lowerFree :: Semiring s => Free s -> s
lowerFree = runFree id
liftFree :: a -> Free a
liftFree = Free . flip Map.singleton one . pure
rep :: Monoid m => m -> Natural -> m
rep x = go
where
go 0 = mempty
go 1 = x
go n
| even n = r `mappend` r
| otherwise = x `mappend` r `mappend` r
where
r = go (n `div` 2)
{-# INLINE rep #-}
infixr 9 #.
(#.) :: Coercible b c => (b -> c) -> (a -> b) -> a -> c
(#.) _ = coerce
{-# INLINE (#.) #-}
infixr 9 .#
(.#) :: Coercible a b => (b -> c) -> (a -> b) -> a -> c
(.#) f _ = coerce f
{-# INLINE (.#) #-}
#endif
#endif