git-subtree-dir: users/glittershark/xanthous git-subtree-mainline:91f53f02d8git-subtree-split:53b56744f4
227 lines
7.3 KiB
Haskell
227 lines
7.3 KiB
Haskell
{-# LANGUAGE PartialTypeSignatures #-}
|
|
{-# LANGUAGE UndecidableInstances #-}
|
|
{-# LANGUAGE QuantifiedConstraints #-}
|
|
{-# LANGUAGE StandaloneDeriving #-}
|
|
{-# LANGUAGE PolyKinds #-}
|
|
--------------------------------------------------------------------------------
|
|
module Xanthous.Data.NestedMap
|
|
( NestedMapVal(..)
|
|
, NestedMap(..)
|
|
, lookup
|
|
, lookupVal
|
|
, insert
|
|
|
|
-- *
|
|
, (:->)
|
|
, BifunctorFunctor'(..)
|
|
, BifunctorMonad'(..)
|
|
) where
|
|
--------------------------------------------------------------------------------
|
|
import Xanthous.Prelude hiding (lookup, foldMap)
|
|
import qualified Xanthous.Prelude as P
|
|
--------------------------------------------------------------------------------
|
|
import Test.QuickCheck
|
|
import Data.Aeson
|
|
import Data.Function (fix)
|
|
import Data.Foldable (Foldable(..))
|
|
import Data.List.NonEmpty (NonEmpty(..))
|
|
import qualified Data.List.NonEmpty as NE
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Natural transformations on bifunctors
|
|
type (:->) p q = forall a b. p a b -> q a b
|
|
infixr 0 :->
|
|
|
|
class (forall b. Bifunctor b => Bifunctor (t b)) => BifunctorFunctor' t where
|
|
bifmap' :: (Bifunctor p, Bifunctor q) => (p :-> q) -> t p :-> t q
|
|
|
|
class BifunctorFunctor' t => BifunctorMonad' t where
|
|
bireturn' :: (Bifunctor p) => p :-> t p
|
|
|
|
bibind' :: (Bifunctor p, Bifunctor q) => (p :-> t q) -> t p :-> t q
|
|
bibind' f = bijoin' . bifmap' f
|
|
|
|
bijoin' :: (Bifunctor p) => t (t p) :-> t p
|
|
bijoin' = bibind' id
|
|
|
|
{-# MINIMAL bireturn', (bibind' | bijoin') #-}
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
data NestedMapVal m k v = Val v | Nested (NestedMap m k v)
|
|
|
|
deriving stock instance
|
|
( forall k' v'. (Show k', Show v') => Show (m k' v')
|
|
, Show k
|
|
, Show v
|
|
) => Show (NestedMapVal m k v)
|
|
|
|
deriving stock instance
|
|
( forall k' v'. (Eq k', Eq v') => Eq (m k' v')
|
|
, Eq k
|
|
, Eq v
|
|
) => Eq (NestedMapVal m k v)
|
|
|
|
instance
|
|
forall m k v.
|
|
( Arbitrary (m k v)
|
|
, Arbitrary (m k (NestedMapVal m k v))
|
|
, Arbitrary k
|
|
, Arbitrary v
|
|
, IsMap (m k (NestedMapVal m k v))
|
|
, MapValue (m k (NestedMapVal m k v)) ~ (NestedMapVal m k v)
|
|
, ContainerKey (m k (NestedMapVal m k v)) ~ k
|
|
) => Arbitrary (NestedMapVal m k v) where
|
|
arbitrary = sized . fix $ \gen n ->
|
|
let nst = fmap (NestedMap . mapFromList)
|
|
. listOf
|
|
$ (,) <$> arbitrary @k <*> gen (n `div` 2)
|
|
in if n == 0
|
|
then Val <$> arbitrary
|
|
else oneof [ Val <$> arbitrary
|
|
, Nested <$> nst]
|
|
shrink (Val v) = Val <$> shrink v
|
|
shrink (Nested mkv) = Nested <$> shrink mkv
|
|
|
|
instance Functor (m k) => Functor (NestedMapVal m k) where
|
|
fmap f (Val v) = Val $ f v
|
|
fmap f (Nested m) = Nested $ fmap f m
|
|
|
|
instance Bifunctor m => Bifunctor (NestedMapVal m) where
|
|
bimap _ g (Val v) = Val $ g v
|
|
bimap f g (Nested m) = Nested $ bimap f g m
|
|
|
|
instance BifunctorFunctor' NestedMapVal where
|
|
bifmap' _ (Val v) = Val v
|
|
bifmap' f (Nested m) = Nested $ bifmap' f m
|
|
|
|
instance (ToJSONKey k, ToJSON v, ToJSON (m k (NestedMapVal m k v)))
|
|
=> ToJSON (NestedMapVal m k v) where
|
|
toJSON (Val v) = toJSON v
|
|
toJSON (Nested m) = toJSON m
|
|
|
|
instance Foldable (m k) => Foldable (NestedMapVal m k) where
|
|
foldMap f (Val v) = f v
|
|
foldMap f (Nested m) = foldMap f m
|
|
|
|
-- _NestedMapVal
|
|
-- :: forall m k v m' k' v'.
|
|
-- ( IsMap (m k v), IsMap (m' k' v')
|
|
-- , IsMap (m [k] v), IsMap (m' [k'] v')
|
|
-- , ContainerKey (m k v) ~ k, ContainerKey (m' k' v') ~ k'
|
|
-- , ContainerKey (m [k] v) ~ [k], ContainerKey (m' [k'] v') ~ [k']
|
|
-- , MapValue (m k v) ~ v, MapValue (m' k' v') ~ v'
|
|
-- , MapValue (m [k] v) ~ v, MapValue (m' [k'] v') ~ v'
|
|
-- )
|
|
-- => Iso (NestedMapVal m k v)
|
|
-- (NestedMapVal m' k' v')
|
|
-- (m [k] v)
|
|
-- (m' [k'] v')
|
|
-- _NestedMapVal = iso hither yon
|
|
-- where
|
|
-- hither :: NestedMapVal m k v -> m [k] v
|
|
-- hither (Val v) = singletonMap [] v
|
|
-- hither (Nested m) = bimap _ _ $ m ^. _NestedMap
|
|
-- yon = _
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
newtype NestedMap m k v = NestedMap (m k (NestedMapVal m k v))
|
|
|
|
deriving stock instance
|
|
( forall k' v'. (Eq k', Eq v') => Eq (m k' v')
|
|
, Eq k
|
|
, Eq v
|
|
) => Eq (NestedMap m k v)
|
|
|
|
deriving stock instance
|
|
( forall k' v'. (Show k', Show v') => Show (m k' v')
|
|
, Show k
|
|
, Show v
|
|
) => Show (NestedMap m k v)
|
|
|
|
instance Arbitrary (m k (NestedMapVal m k v))
|
|
=> Arbitrary (NestedMap m k v) where
|
|
arbitrary = NestedMap <$> arbitrary
|
|
shrink (NestedMap m) = NestedMap <$> shrink m
|
|
|
|
instance Functor (m k) => Functor (NestedMap m k) where
|
|
fmap f (NestedMap m) = NestedMap $ fmap (fmap f) m
|
|
|
|
instance Bifunctor m => Bifunctor (NestedMap m) where
|
|
bimap f g (NestedMap m) = NestedMap $ bimap f (bimap f g) m
|
|
|
|
instance BifunctorFunctor' NestedMap where
|
|
bifmap' f (NestedMap m) = NestedMap . f $ bimap id (bifmap' f) m
|
|
|
|
instance (ToJSONKey k, ToJSON v, ToJSON (m k (NestedMapVal m k v)))
|
|
=> ToJSON (NestedMap m k v) where
|
|
toJSON (NestedMap m) = toJSON m
|
|
|
|
instance Foldable (m k) => Foldable (NestedMap m k) where
|
|
foldMap f (NestedMap m) = foldMap (foldMap f) m
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
lookup
|
|
:: ( IsMap (m k (NestedMapVal m k v))
|
|
, MapValue (m k (NestedMapVal m k v)) ~ (NestedMapVal m k v)
|
|
, ContainerKey (m k (NestedMapVal m k v)) ~ k
|
|
)
|
|
=> NonEmpty k
|
|
-> NestedMap m k v
|
|
-> Maybe (NestedMapVal m k v)
|
|
lookup (p :| []) (NestedMap vs) = P.lookup p vs
|
|
lookup (p :| (p₁ : ps)) (NestedMap vs) = P.lookup p vs >>= \case
|
|
(Val _) -> Nothing
|
|
(Nested vs') -> lookup (p₁ :| ps) vs'
|
|
|
|
lookupVal
|
|
:: ( IsMap (m k (NestedMapVal m k v))
|
|
, MapValue (m k (NestedMapVal m k v)) ~ (NestedMapVal m k v)
|
|
, ContainerKey (m k (NestedMapVal m k v)) ~ k
|
|
)
|
|
=> NonEmpty k
|
|
-> NestedMap m k v
|
|
-> Maybe v
|
|
lookupVal ks m
|
|
| Just (Val v) <- lookup ks m = Just v
|
|
| otherwise = Nothing
|
|
|
|
insert
|
|
:: ( IsMap (m k (NestedMapVal m k v))
|
|
, MapValue (m k (NestedMapVal m k v)) ~ (NestedMapVal m k v)
|
|
, ContainerKey (m k (NestedMapVal m k v)) ~ k
|
|
)
|
|
=> NonEmpty k
|
|
-> v
|
|
-> NestedMap m k v
|
|
-> NestedMap m k v
|
|
insert (k :| []) v (NestedMap m) = NestedMap $ P.insertMap k (Val v) m
|
|
insert (k₁ :| (k₂ : ks)) v (NestedMap m) = NestedMap $ alterMap upd k₁ m
|
|
where
|
|
upd (Just (Nested nm)) = Just . Nested $ insert (k₂ :| ks) v nm
|
|
upd _ = Just $
|
|
let (kΩ :| ks') = NE.reverse (k₂ :| ks)
|
|
in P.foldl'
|
|
(\m' k -> Nested . NestedMap . singletonMap k $ m')
|
|
(Nested . NestedMap . singletonMap kΩ $ Val v)
|
|
ks'
|
|
|
|
-- _NestedMap
|
|
-- :: ( IsMap (m k v), IsMap (m' k' v')
|
|
-- , IsMap (m (NonEmpty k) v), IsMap (m' (NonEmpty k') v')
|
|
-- , ContainerKey (m k v) ~ k, ContainerKey (m' k' v') ~ k'
|
|
-- , ContainerKey (m (NonEmpty k) v) ~ (NonEmpty k)
|
|
-- , ContainerKey (m' (NonEmpty k') v') ~ (NonEmpty k')
|
|
-- , MapValue (m k v) ~ v, MapValue (m' k' v') ~ v'
|
|
-- , MapValue (m (NonEmpty k) v) ~ v, MapValue (m' (NonEmpty k') v') ~ v'
|
|
-- )
|
|
-- => Iso (NestedMap m k v)
|
|
-- (NestedMap m' k' v')
|
|
-- (m (NonEmpty k) v)
|
|
-- (m' (NonEmpty k') v')
|
|
-- _NestedMap = iso undefined yon
|
|
-- where
|
|
-- hither (NestedMap m) = undefined . mapToList $ m
|
|
-- yon mkv = undefined
|