packages feed

htree-0.1.1.0: test/Spec/HTree/Orphans.hs

{-# LANGUAGE ImpredicativeTypes #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NoOverloadedLists #-}
{-# OPTIONS_GHC -Wno-orphans #-}

module Spec.HTree.Orphans where

import Data.HTree (HTree (HNode))
import Data.HTree.Existential (EList, ETree, Has (Proves), Some (MkSome), Some2 (MkSome2))
import Data.HTree.Families (Both)
import Data.HTree.List (HList (HCons, HNil))
import Data.Maybe (catMaybes)
import Data.Proxy (Proxy (Proxy))
import Data.Tree (Tree (Node))
import Spec.HTree.Helpers (liftedWith)
import Spec.HTree.TH (discoverInstancesTypeable)
import Test.QuickCheck.Arbitrary (Arbitrary (arbitrary))
import Test.QuickCheck.Gen (Gen, oneof)
import Test.QuickCheck.Instances ()
import Type.Reflection (Typeable, eqTypeRep, typeRep, (:~~:) (HRefl))

embedType :: [Some (Has Typeable Gen)]
embedType = liftedWith $$(discoverInstancesTypeable @Arbitrary) \(Proves (Proxy :: Proxy a)) ->
  MkSome $ Proves $ arbitrary @a

embedArbOrd :: [Some (Has (Both Typeable Ord) Gen)]
embedArbOrd =
  catMaybes $ concat $ liftedWith $$(discoverInstancesTypeable @Ord) \(Proves (Proxy :: Proxy a)) ->
    liftedWith $$(discoverInstancesTypeable @Arbitrary) \(Proves (Proxy :: Proxy b)) ->
      case eqTypeRep (typeRep @a) (typeRep @b) of
        Nothing -> Nothing
        Just HRefl -> Just (MkSome (Proves $ arbitrary @a))

toEList :: [Some x] -> EList x
toEList [] = MkSome2 HNil
toEList (MkSome x : xs) =
  case toEList xs of
    MkSome2 t -> MkSome2 (HCons x t)

toETree :: Tree (Some f) -> ETree f
toETree (Node (MkSome t) []) = MkSome2 (HNode t HNil)
toETree (Node t' (t : ts)) =
  case (toETree t, toETree (Node t' ts)) of
    (MkSome2 ht, MkSome2 (HNode ht' hts)) -> MkSome2 (HNode ht' (HCons ht hts))

instance Applicative f => Arbitrary (EList (Has Typeable f)) where
  arbitrary = toEList <$> arbitrary

instance Applicative f => Arbitrary (ETree (Has Typeable f)) where
  arbitrary = toETree <$> arbitrary

instance Applicative f => Arbitrary (Some (Has Typeable f)) where
  arbitrary = oneof $ liftedWith embedType \(Proves gen :: Has Typeable Gen b) ->
    MkSome . Proves . pure <$> gen

instance {-# OVERLAPPING #-} Applicative f => Arbitrary (Some (Has Typeable (Has Ord f))) where
  arbitrary = oneof $ liftedWith embedArbOrd \(Proves gen :: Has (Both Typeable Ord) Gen b) ->
    MkSome . Proves . Proves . pure <$> gen

instance (forall x. Eq x => Eq (f x), Typeable f) => Eq (Some (Has Typeable (Has Ord f))) where
  MkSome (Proves (Proves x)) == MkSome (Proves (Proves y)) =
    MkSome (Proves @Typeable (Proves @Eq x)) == MkSome (Proves @Typeable (Proves @Eq y))