module Test.Function.Idempotent where
import Data.List (unfoldr)
import Numeric.Natural (Natural(..))
import Test.Util
projective :: Eq r => (r -> r) -> (r -> r) -> r -> Bool
projective = projective_on (==)
projective_on :: Rel s -> (r -> s) -> (s -> s) -> r -> Bool
projective_on (~~) f g r = g (f r) ~~ f r
idempotent :: Eq r => (r -> r) -> r -> Bool
idempotent f = idempotent_on (==) f
idempotent_on :: Rel r -> (r -> r) -> r -> Bool
idempotent_on (~~) f = projective_on (~~) f f
idempotent_k :: Eq r => Natural -> (r -> r) -> r -> Bool
idempotent_k k f r = k >= 1 ==> foldr (.) id fs r == f r
where fs = (`unfoldr` k) $ \m -> if m==1 then Nothing else Just (f,m-1)