-- | General operations on sets module Feldspar.Set where -- | A 'Set' is an *over-approximation* of a set of values. The class does not -- care about how the set is interpreted, but it only makes sense to use -- interpretations for which the operations are sound. class Eq a => Set a where empty :: a universal :: a -- | Union (\/) :: a -> a -> a -- | Intersection (/\) :: a -> a -> a -- | Approximates all sets as @()@, which is the 'universal' set. instance Set () where empty = () universal = () () \/ () = () () /\ () = () -- | Set product instance (Set a, Set b) => Set (a,b) where empty = (empty,empty) universal = (universal,universal) (a1,a2) \/ (b1,b2) = (a1 \/ b1, a2 \/ b2) (a1,a2) /\ (b1,b2) = (a1 /\ b1, a2 /\ b2) -- | Three-way product instance (Set a, Set b, Set c) => Set (a,b,c) where empty = (empty,empty,empty) universal = (universal,universal,universal) (a1,a2,a3) \/ (b1,b2,b3) = (a1 \/ b1, a2 \/ b2, a3 \/ b3) (a1,a2,a3) /\ (b1,b2,b3) = (a1 /\ b1, a2 /\ b2, a3 /\ b3) -- | Four-way product instance (Set a, Set b, Set c, Set d) => Set (a,b,c,d) where empty = (empty,empty,empty,empty) universal = (universal,universal,universal,universal) (a1,a2,a3,a4) \/ (b1,b2,b3,b4) = (a1 \/ b1, a2 \/ b2, a3 \/ b3, a4 \/ b4) (a1,a2,a3,a4) /\ (b1,b2,b3,b4) = (a1 /\ b1, a2 /\ b2, a3 /\ b3, a4 /\ b4) unions :: Set a => [a] -> a unions = foldr (\/) empty intersections :: Set a => [a] -> a intersections = foldr (/\) universal -- Computing fixed points -- | Take the fixed point of a monotonic function. The second argument is -- an initial element. A sensible default for the initial element is -- 'empty'. fixedPoint :: Set a => (a -> a) -> a -> a fixedPoint f a | fa == a = fa | otherwise = fixedPoint f fa where fa = f a \/ a -- | Much like 'fixedPoint' but keeps track of the number of iterations -- in the fixed point iteration. Useful for defining widening operators. indexedFixedPoint :: Set a => (Int -> a -> a) -> a -> (a,Int) indexedFixedPoint f a = go 0 f a where go i f a | fa == a = (fa,i) | otherwise = go (i+1) f fa where fa = f i a \/ a -- | The type of widening operators. A widening operator modifies a -- function that is subject to fixed point analysis. A widening -- operator introduces approximations in order to guarantee (fast) -- termination of the fixed point analysis. type Widening a = (Int -> a -> a) -> (Int -> a -> a) -- | A widening operator which defaults to 'universal' when the number of -- iterations goes over the specified value. cutOffAt :: Set a => Int -> Widening a cutOffAt n f i a | i >= n = universal | otherwise = f i a