packages feed

witness-0.5: src/Data/Witness/Finite.hs

{-# OPTIONS -fno-warn-orphans #-}

module Data.Witness.Finite where

import Data.Constraint
import Data.Countable
import Data.Functor.Const
import Data.Functor.Identity
import Data.Kind
import Data.List (intercalate)
import Data.Searchable
import Data.Type.Equality
import Data.Witness.All
import Data.Witness.Any
import Data.Witness.Constraint
import Prelude

class FiniteWitness (w :: k -> Type) where
    assembleWitnessF :: Applicative m => (forall t. w t -> m (f t)) -> m (AllF w f)

instance (TestEquality w, FiniteWitness w) => Countable (AnyW w) where
    countPrevious = finiteCountPrevious
    countMaybeNext = finiteCountMaybeNext

instance (TestEquality w, FiniteWitness w) => Searchable (AnyW w) where
    search = finiteSearch

instance (TestEquality w, FiniteWitness w) => Finite (AnyW w) where
    assemble ::
           forall b f. Applicative f
        => (AnyW w -> f b)
        -> f (AnyW w -> b)
    assemble afb =
        fmap (\(MkAllF wtcb) (MkAnyW wt) -> getConst $ wtcb wt) $ assembleWitnessF $ \wt -> fmap Const $ afb $ MkAnyW wt
    allValues = getConst $ assembleWitnessF $ \wt -> Const [MkAnyW wt]

allWitnesses :: FiniteWitness w => [AnyW w]
allWitnesses = getConst $ assembleWitnessF $ \wt -> Const [MkAnyW wt]

instance (FiniteWitness w, AllWitnessConstraint Show w, WitnessConstraint Show w) => Show (AllValue w) where
    show (MkAllValue wtt) = let
        showItem :: AnyW w -> String
        showItem (MkAnyW wt) =
            showAllWitness wt ++
            " -> " ++
            case witnessConstraint @_ @Show wt of
                Dict -> show (wtt wt)
        in "{" ++ intercalate "," (fmap showItem allWitnesses) ++ "}"

assembleWitness :: (FiniteWitness w, Applicative m) => (forall t. w t -> m t) -> m (AllValue w)
assembleWitness wtmt = fmap allFToAllValue $ assembleWitnessF $ \wt -> fmap Identity $ wtmt wt