2{-# LANGUAGE DeriveDataTypeable #-}
3{-# LANGUAGE DeriveFunctor #-}
4{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE FlexibleInstances #-}
7{-# LANGUAGE LambdaCase #-}
8{-# LANGUAGE MultiParamTypeClasses #-}
9{-# LANGUAGE PolyKinds #-}
10{-# LANGUAGE RankNTypes #-}
11{-# LANGUAGE ScopedTypeVariables #-}
12{-# LANGUAGE StandaloneDeriving #-}
13-- | This module provides types and functions with no particular theme, but
14-- which are relevant to the use of 'Functor'-based datastructures like
15-- 'Data.Dependent.Map.DMap'.
16module Data.Functor.Misc
27 -- * Convenience functions for DMap
28 , mapWithFunctorToDMap
29 , intMapWithFunctorToDMap
30 , mapKeyValuePairsMonotonic
39import Control.Applicative ((<$>))
40import Data.Dependent.Map (DMap)
41import qualified Data.Dependent.Map as DMap
42import Data.Dependent.Sum
43import Data.Functor.Identity
44import Data.GADT.Compare
46import Data.IntMap (IntMap)
47import qualified Data.IntMap as IntMap
49import qualified Data.Map as Map
50import Data.Some (Some, mkSome)
52import Data.Type.Equality ((:~:)(Refl))
53import Data.Typeable hiding (Refl)
55--------------------------------------------------------------------------------
57--------------------------------------------------------------------------------
59-- | 'Const2' stores a value of a given type 'k' and ensures that a particular
60-- type 'v' is always given for the last type parameter
61data Const2 :: * -> x -> x -> * where
62 Const2 :: k -> Const2 k v v
65-- | Extract the value from a Const2
66unConst2 :: Const2 k v v' -> k
67unConst2 (Const2 k) = k
69deriving instance Eq k => Eq (Const2 k v v')
70deriving instance Ord k => Ord (Const2 k v v')
71deriving instance Show k => Show (Const2 k v v')
72deriving instance Read k => Read (Const2 k v v)
74instance Show k => GShow (Const2 k v) where
75 gshowsPrec n x@(Const2 _) = showsPrec n x
77instance Eq k => GEq (Const2 k v) where
78 geq (Const2 a) (Const2 b) =
83instance Ord k => GCompare (Const2 k v) where
84 gcompare (Const2 a) (Const2 b) = case compare a b of
89-- | Convert a 'DMap' to a regular 'Map'
90dmapToMap :: DMap (Const2 k v) Identity -> Map k v
91dmapToMap = Map.fromDistinctAscList . map (\(Const2 k :=> Identity v) -> (k, v)) . DMap.toAscList
93-- | Convert a 'DMap' to an 'IntMap'
94dmapToIntMap :: DMap (Const2 IntMap.Key v) Identity -> IntMap v
95dmapToIntMap = IntMap.fromDistinctAscList . map (\(Const2 k :=> Identity v) -> (k, v)) . DMap.toAscList
97-- | Convert a 'DMap' to a regular 'Map', applying the given function to remove
98-- the wrapping 'Functor'
99dmapToMapWith :: (f v -> v') -> DMap (Const2 k v) f -> Map k v'
100dmapToMapWith f = Map.fromDistinctAscList . map (\(Const2 k :=> v) -> (k, f v)) . DMap.toAscList
102-- | Convert a regular 'Map' to a 'DMap'
103mapToDMap :: Map k v -> DMap (Const2 k v) Identity
104mapToDMap = DMap.fromDistinctAscList . map (\(k, v) -> Const2 k :=> Identity v) . Map.toAscList
106-- | Convert a regular 'Map', where the values are already wrapped in a functor,
108mapWithFunctorToDMap :: Map k (f v) -> DMap (Const2 k v) f
109mapWithFunctorToDMap = DMap.fromDistinctAscList . map (\(k, v) -> Const2 k :=> v) . Map.toAscList
111-- | Convert a regular 'IntMap', where the values are already wrapped in a
112-- functor, to a 'DMap'
113intMapWithFunctorToDMap :: IntMap (f v) -> DMap (Const2 IntMap.Key v) f
114intMapWithFunctorToDMap = DMap.fromDistinctAscList . map (\(k, v) -> Const2 k :=> v) . IntMap.toAscList
116-- | Convert a 'DMap' to a regular 'Map' by forgetting the types associated with
117-- the keys, using a function to remove the wrapping 'Functor'
118weakenDMapWith :: (forall a. v a -> v') -> DMap k v -> Map (Some k) v'
119weakenDMapWith f = Map.fromDistinctAscList . map (\(k :=> v) -> (mkSome k, f v)) . DMap.toAscList
121--------------------------------------------------------------------------------
123--------------------------------------------------------------------------------
125-- | 'WrapArg' can be used to tag a value in one functor with a type
126-- representing another functor. This was primarily used with dependent-map <
127-- 0.2, in which the value type was not wrapped in a separate functor.
128data WrapArg :: (k -> *) -> (k -> *) -> * -> * where
129 WrapArg :: f a -> WrapArg g f (g a)
131deriving instance Eq (f a) => Eq (WrapArg g f (g' a))
132deriving instance Ord (f a) => Ord (WrapArg g f (g' a))
133deriving instance Show (f a) => Show (WrapArg g f (g' a))
134deriving instance Read (f a) => Read (WrapArg g f (g a))
136instance GEq f => GEq (WrapArg g f) where
137 geq (WrapArg a) (WrapArg b) = (\Refl -> Refl) <$> geq a b
139instance GCompare f => GCompare (WrapArg g f) where
140 gcompare (WrapArg a) (WrapArg b) = case gcompare a b of
145--------------------------------------------------------------------------------
146-- Convenience functions for DMap
147--------------------------------------------------------------------------------
149-- | Map over all key/value pairs in a 'DMap', potentially altering the key as
150-- well as the value. The provided function MUST preserve the ordering of the
151-- keys, or the resulting 'DMap' will be malformed.
152mapKeyValuePairsMonotonic :: (DSum k v -> DSum k' v') -> DMap k v -> DMap k' v'
153mapKeyValuePairsMonotonic f = DMap.fromDistinctAscList . map f . DMap.toAscList
155{-# INLINE combineDMapsWithKey #-}
156-- | Union two 'DMap's of different types, yielding another type. Each key that
157-- is present in either input map will be present in the output.
158combineDMapsWithKey :: forall f g h i.
160 => (forall a. f a -> These (g a) (h a) -> i a)
164combineDMapsWithKey f mg mh = DMap.fromList $ go (DMap.toList mg) (DMap.toList mh)
165 where go :: [DSum f g] -> [DSum f h] -> [DSum f i]
166 go [] hs = map (\(hk :=> hv) -> hk :=> f hk (That hv)) hs
167 go gs [] = map (\(gk :=> gv) -> gk :=> f gk (This gv)) gs
168 go gs@((gk :=> gv) : gs') hs@((hk :=> hv) : hs') = case gk `gcompare` hk of
169 GLT -> (gk :=> f gk (This gv)) : go gs' hs
170 GEQ -> (gk :=> f gk (These gv hv)) : go gs' hs'
171 GGT -> (hk :=> f hk (That hv)) : go gs hs'
173-- | Extract the values of a 'DMap' of 'EitherTag's.
174dmapToThese :: DMap (EitherTag a b) Identity -> Maybe (These a b)
175dmapToThese m = case (DMap.lookup LeftTag m, DMap.lookup RightTag m) of
176 (Nothing, Nothing) -> Nothing
177 (Just (Identity a), Nothing) -> Just $ This a
178 (Nothing, Just (Identity b)) -> Just $ That b
179 (Just (Identity a), Just (Identity b)) -> Just $ These a b
181-- | Tag type for 'Either' to use it as a 'DSum'.
182data EitherTag l r a where
183 LeftTag :: EitherTag l r l
184 RightTag :: EitherTag l r r
187deriving instance Show (EitherTag l r a)
188deriving instance Eq (EitherTag l r a)
189deriving instance Ord (EitherTag l r a)
191instance GEq (EitherTag l r) where
192 geq a b = case (a, b) of
193 (LeftTag, LeftTag) -> Just Refl
194 (RightTag, RightTag) -> Just Refl
197instance GCompare (EitherTag l r) where
198 gcompare a b = case (a, b) of
199 (LeftTag, LeftTag) -> GEQ
200 (LeftTag, RightTag) -> GLT
201 (RightTag, LeftTag) -> GGT
202 (RightTag, RightTag) -> GEQ
204instance GShow (EitherTag l r) where
205 gshowsPrec _ a = case a of
206 LeftTag -> showString "LeftTag"
207 RightTag -> showString "RightTag"
209-- | Convert 'Either' to a 'DSum'. Inverse of 'dsumToEither'.
210eitherToDSum :: Either a b -> DSum (EitherTag a b) Identity
212 Left a -> (LeftTag :=> Identity a)
213 Right b -> (RightTag :=> Identity b)
215-- | Convert 'DSum' to 'Either'. Inverse of 'eitherToDSum'.
216dsumToEither :: DSum (EitherTag a b) Identity -> Either a b
218 (LeftTag :=> Identity a) -> Left a
219 (RightTag :=> Identity b) -> Right b
221--------------------------------------------------------------------------------
223--------------------------------------------------------------------------------
225-- | We can't use @Compose Maybe@ instead of 'ComposeMaybe', because that would
226-- make the 'f' parameter have a nominal type role. We need f to be
227-- representational so that we can use safe 'coerce'.
228newtype ComposeMaybe f a =
229 ComposeMaybe { getComposeMaybe :: Maybe (f a) } deriving (Show, Eq, Ord)
231deriving instance Functor f => Functor (ComposeMaybe f)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list