range-0.3.2.1: Data/Range/Algebra/Internal.hs
{-# LANGUAGE Safe #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
module Data.Range.Algebra.Internal where
import Prelude hiding (const)
import Data.Range.RangeInternal
import Control.Monad.Free
import Data.Functor.Classes
data RangeExprF r
= Invert r
| Union r r
| Intersection r r
| Difference r r
deriving (Show, Eq, Functor)
instance Eq1 RangeExprF where
liftEq eq (Invert a) (Invert b) = eq a b
liftEq eq (Union a c) (Union b d) = eq a b && eq c d
liftEq eq (Intersection a c) (Intersection b d) = eq a b && eq c d
liftEq eq (Difference a c) (Difference b d) = eq a b && eq c d
liftEq _ _ _ = False
instance Show1 RangeExprF where
liftShowsPrec showPrec _ p (Invert x) = showString "not " . showParen True (showPrec (p + 1) x)
liftShowsPrec showPrec _ p (Union a b) =
showPrec (p + 1) a .
showString " \\/ " .
showPrec (p + 1) b
liftShowsPrec showPrec _ p (Intersection a b) =
showPrec (p + 1) a .
showString " /\\ " .
showPrec (p + 1) b
liftShowsPrec showPrec _ p (Difference a b) =
showPrec (p + 1) a .
showString " - " .
showPrec (p + 1) b
-- | An expression tree representing a sequence of set operations on ranges.
-- Construct trees with 'Data.Range.Algebra.const', 'Data.Range.Algebra.union',
-- 'Data.Range.Algebra.intersection', 'Data.Range.Algebra.difference', and
-- 'Data.Range.Algebra.invert', then collapse the tree with 'Data.Range.Algebra.eval'.
--
-- The type parameter @a@ is the range representation the tree will eventually
-- evaluate to (e.g. @['Data.Range.Range' Integer]@ or @Integer -> 'Bool'@).
--
-- @RangeExpr@ is a 'Functor', so you can map over the leaf values before evaluation.
newtype RangeExpr a = RangeExpr { getFree :: Free RangeExprF a }
deriving (Show, Eq, Functor)
-- | The type of an evaluation function for a 'RangeExpr'. You will not normally
-- need to reference this alias directly; it exists to express the signature of
-- 'Data.Range.Algebra.eval'.
--
-- Concretely, @Algebra f a = f a -> a@, meaning: given a functor @f@ applied to
-- an already-evaluated @a@, produce the final @a@. The 'Control.Monad.Free.iter'
-- function from the @free@ package drives the bottom-up fold.
type Algebra f a = f a -> a
rangeMergeAlgebra :: (Ord a) => Algebra RangeExprF (RangeMerge a)
rangeMergeAlgebra (Invert a) = invertRM a
rangeMergeAlgebra (Union a b) = a `unionRangeMerges` b
rangeMergeAlgebra (Intersection a b) = a `intersectionRangeMerges` b
rangeMergeAlgebra (Difference a b) = a `intersectionRangeMerges` invertRM b