{-| This module provides the 'Sized' class. Instances of this class are typically collection data types for infinite sets of values with a finite number of values of any given size. A simple example is "Control.Enumerable.Count" that just counts the number of values of each size. "Control.Enumerable.Values" provides all values of a given size. <https://hackage.haskell.org/package/testing-feat FEAT> provides any value in the set much more efficiently. -} module Control.Sized (module Control.Applicative, Sized(..), kbits) where import Control.Applicative -- | A sized functor is an applicative functor extended with a notion of cost/size of contained values. This is useful for any type of bounded recursion over infinite sets, most notably for various kind of enumerations. -- -- The intention is that every sized functor definition models a (usually) infinite set (technically a bag) with a finite number of values of any given size. As long as every cyclic (recursive) definition has at least one application of pay, this invariant is guaranteed. -- -- The module "Control.Enumerable" provides sized functor definitions for a lot of data types, such that the size of a value is the number of constructor applications it contains. It also allows deriving these functors for any user defined data type (using Template Haskell). class Alternative f => Sized f where -- | Increases the cost/size of all values in the given set. pay :: f a -> f a -- | Default: @pair a b = (,) <$> a <*> b@. pair :: f a -> f b -> f (a,b) pair a b = (,) <$> a <*> b -- | Default: @aconcat = foldr (\<|>) empty@ aconcat :: [f a] -> f a aconcat [] = empty aconcat xs = foldr1 (<|>) xs {- | Finite numeric types. @fin n@ contains all non-negative numbers below n. This definition is flat, all integers have the same size. Implementing this function efficiently will have a great impact on applications that use a lot of bounded numeric types (e.g. Int). Default: aconcat (map pure [0..n-1]) -} fin :: Integer -> f Integer fin n = aconcat (map pure [0..n-1]) {- |Same as 'fin' but the size of values may differ. By default, the size of an integer is the number of significant bits in its binary representation. In other words, 0 has size zero, the values for size k>0 in @finBits n@ are in the interval @(2^(k-1),min (2^k-1) n)@. -} finSized :: Integer -> f Integer finSized = stdFinBits -- | Non-negative integers. By default, the size of an integer is the number of digits in its binary representation. naturals :: f Integer naturals = stdNaturals stdNaturals :: Sized f => f Integer stdNaturals = pure 0 <|> go 0 where go n = pay $ ((2^n)+) <$> fin (2^n) <|> (go (n+1)) stdNaturals' :: Sized f => f Integer stdNaturals' = pure 0 <|> go 1 where go n = pay $ (n+) <$> fin n <|> go (2*n) stdFinBits :: Sized f => Integer -> f Integer stdFinBits i | i <= 0 = empty stdFinBits i = pure 0 <|> go 1 where go n | n <= lim = pay $ (n+) <$> fin n <|> go (2*n) go n | n >= i = empty go n = pay $ (n+) <$> fin (i-n) lim = i `div` 2 -- Non-negative integers of a given maximal number of bits. kbits :: Sized f => Int -> f Integer kbits k = finSized (2^k) -- integers :: Sized f => (Int -> (Integer,Integer)) -> f Integer -- integers = -- ints :: Sized f => Int -> (Int -> (Integer,Integer)) -> f Integer