module Util.Universe where
import Prelude hiding ((.), id)
import Control.Arrow
import Control.Category
import Control.Monad
import Data.Functor.Classes
import Data.Functor.Compose
import qualified Data.List as List
import Data.Maybe
import Data.Universe.Class
import Data.Universe.Instances.Base ()
import Numeric.Natural
newtype Fn a b = Fn { unFn :: a -> b }
deriving (Semigroup, Monoid, Universe, Finite, Functor, Applicative, Monad,
Category, Arrow, ArrowApply, ArrowChoice, ArrowLoop)
instance (Universe a, Eq b) => Eq (Fn a b) where (==) = eq1
instance Universe a => Foldable (Fn a) where
foldMap f (Fn φ) = foldMap (f . φ) universe
instance (Eq a, Finite a) => Traversable (Fn a) where
sequenceA (Fn φ) =
Fn . (\ bs a -> fromJust $ List.lookup a bs) . getCompose <$>
traverse φ (Compose $ join (,) <$> universe)
instance Universe a => Eq1 (Fn a) where
liftEq eq (Fn φ) (Fn χ) = liftEq eq (φ <$> universe) (χ <$> universe)
universalIndex :: (Eq a, Universe a) => a -> Natural
universalIndex a = List.genericLength $ List.takeWhile (/= a) universe