2{-# LANGUAGE DeriveDataTypeable #-}
3{-# LANGUAGE DeriveFunctor #-}
4{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE FlexibleInstances #-}
7{-# LANGUAGE LambdaCase #-}
8{-# LANGUAGE MultiParamTypeClasses #-}
9{-# LANGUAGE PatternSynonyms #-}
10{-# LANGUAGE PolyKinds #-}
11{-# LANGUAGE RankNTypes #-}
12{-# LANGUAGE ScopedTypeVariables #-}
13{-# LANGUAGE StandaloneDeriving #-}
14#ifdef USE_REFLEX_OPTIMIZER
15{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
17-- | This module provides types and functions with no particular theme, but
18-- which are relevant to the use of 'Functor'-based datastructures like
19-- 'Data.Dependent.Map.DMap'.
20module Data.Functor.Misc
31 -- * Convenience functions for DMap
32 , mapWithFunctorToDMap
33 , intMapWithFunctorToDMap
34 , mapKeyValuePairsMonotonic
43import Control.Applicative ((<$>))
44import Control.Monad.Identity
45import Data.Dependent.Map (DMap)
46import qualified Data.Dependent.Map as DMap
47import Data.Dependent.Sum
48import Data.GADT.Compare
50import Data.IntMap (IntMap)
51import qualified Data.IntMap as IntMap
53import qualified Data.Map as Map
54import Data.Some (Some(Some))
56import Data.Typeable hiding (Refl)
58--------------------------------------------------------------------------------
60--------------------------------------------------------------------------------
62-- | 'Const2' stores a value of a given type 'k' and ensures that a particular
63-- type 'v' is always given for the last type parameter
64data Const2 :: * -> x -> x -> * where
65 Const2 :: k -> Const2 k v v
68-- | Extract the value from a Const2
69unConst2 :: Const2 k v v' -> k
70unConst2 (Const2 k) = k
72deriving instance Eq k => Eq (Const2 k v v')
73deriving instance Ord k => Ord (Const2 k v v')
74deriving instance Show k => Show (Const2 k v v')
75deriving instance Read k => Read (Const2 k v v)
77instance Show k => GShow (Const2 k v) where
78 gshowsPrec n x@(Const2 _) = showsPrec n x
80instance Eq k => GEq (Const2 k v) where
81 geq (Const2 a) (Const2 b) =
86instance Ord k => GCompare (Const2 k v) where
87 gcompare (Const2 a) (Const2 b) = case compare a b of
92-- | Convert a 'DMap' to a regular 'Map'
93dmapToMap :: DMap (Const2 k v) Identity -> Map k v
94dmapToMap = Map.fromDistinctAscList . map (\(Const2 k :=> Identity v) -> (k, v)) . DMap.toAscList
96-- | Convert a 'DMap' to an 'IntMap'
97dmapToIntMap :: DMap (Const2 IntMap.Key v) Identity -> IntMap v
98dmapToIntMap = IntMap.fromDistinctAscList . map (\(Const2 k :=> Identity v) -> (k, v)) . DMap.toAscList
100-- | Convert a 'DMap' to a regular 'Map', applying the given function to remove
101-- the wrapping 'Functor'
102dmapToMapWith :: (f v -> v') -> DMap (Const2 k v) f -> Map k v'
103dmapToMapWith f = Map.fromDistinctAscList . map (\(Const2 k :=> v) -> (k, f v)) . DMap.toAscList
105-- | Convert a regular 'Map' to a 'DMap'
106mapToDMap :: Map k v -> DMap (Const2 k v) Identity
107mapToDMap = DMap.fromDistinctAscList . map (\(k, v) -> Const2 k :=> Identity v) . Map.toAscList
109-- | Convert a regular 'Map', where the values are already wrapped in a functor,
111mapWithFunctorToDMap :: Map k (f v) -> DMap (Const2 k v) f
112mapWithFunctorToDMap = DMap.fromDistinctAscList . map (\(k, v) -> Const2 k :=> v) . Map.toAscList
114-- | Convert a regular 'IntMap', where the values are already wrapped in a
115-- functor, to a 'DMap'
116intMapWithFunctorToDMap :: IntMap (f v) -> DMap (Const2 IntMap.Key v) f
117intMapWithFunctorToDMap = DMap.fromDistinctAscList . map (\(k, v) -> Const2 k :=> v) . IntMap.toAscList
119-- | Convert a 'DMap' to a regular 'Map' by forgetting the types associated with
120-- the keys, using a function to remove the wrapping 'Functor'
121weakenDMapWith :: (forall a. v a -> v') -> DMap k v -> Map (Some k) v'
122weakenDMapWith f = Map.fromDistinctAscList . map (\(k :=> v) -> (Some k, f v)) . DMap.toAscList
124--------------------------------------------------------------------------------
126--------------------------------------------------------------------------------
128-- | 'WrapArg' can be used to tag a value in one functor with a type
129-- representing another functor. This was primarily used with dependent-map <
130-- 0.2, in which the value type was not wrapped in a separate functor.
131data WrapArg :: (k -> *) -> (k -> *) -> * -> * where
132 WrapArg :: f a -> WrapArg g f (g a)
134deriving instance Eq (f a) => Eq (WrapArg g f (g' a))
135deriving instance Ord (f a) => Ord (WrapArg g f (g' a))
136deriving instance Show (f a) => Show (WrapArg g f (g' a))
137deriving instance Read (f a) => Read (WrapArg g f (g a))
139instance GEq f => GEq (WrapArg g f) where
140 geq (WrapArg a) (WrapArg b) = (\Refl -> Refl) <$> geq a b
142instance GCompare f => GCompare (WrapArg g f) where
143 gcompare (WrapArg a) (WrapArg b) = case gcompare a b of
148--------------------------------------------------------------------------------
149-- Convenience functions for DMap
150--------------------------------------------------------------------------------
152-- | Map over all key/value pairs in a 'DMap', potentially altering the key as
153-- well as the value. The provided function MUST preserve the ordering of the
154-- keys, or the resulting 'DMap' will be malformed.
155mapKeyValuePairsMonotonic :: (DSum k v -> DSum k' v') -> DMap k v -> DMap k' v'
156mapKeyValuePairsMonotonic f = DMap.fromDistinctAscList . map f . DMap.toAscList
158{-# INLINE combineDMapsWithKey #-}
159-- | Union two 'DMap's of different types, yielding another type. Each key that
160-- is present in either input map will be present in the output.
161combineDMapsWithKey :: forall f g h i.
163 => (forall a. f a -> These (g a) (h a) -> i a)
167combineDMapsWithKey f mg mh = DMap.fromList $ go (DMap.toList mg) (DMap.toList mh)
168 where go :: [DSum f g] -> [DSum f h] -> [DSum f i]
169 go [] hs = map (\(hk :=> hv) -> hk :=> f hk (That hv)) hs
170 go gs [] = map (\(gk :=> gv) -> gk :=> f gk (This gv)) gs
171 go gs@((gk :=> gv) : gs') hs@((hk :=> hv) : hs') = case gk `gcompare` hk of
172 GLT -> (gk :=> f gk (This gv)) : go gs' hs
173 GEQ -> (gk :=> f gk (These gv hv)) : go gs' hs'
174 GGT -> (hk :=> f hk (That hv)) : go gs hs'
176-- | Extract the values of a 'DMap' of 'EitherTag's.
177dmapToThese :: DMap (EitherTag a b) Identity -> Maybe (These a b)
178dmapToThese m = case (DMap.lookup LeftTag m, DMap.lookup RightTag m) of
179 (Nothing, Nothing) -> Nothing
180 (Just (Identity a), Nothing) -> Just $ This a
181 (Nothing, Just (Identity b)) -> Just $ That b
182 (Just (Identity a), Just (Identity b)) -> Just $ These a b
184-- | Tag type for 'Either' to use it as a 'DSum'.
185data EitherTag l r a where
186 LeftTag :: EitherTag l r l
187 RightTag :: EitherTag l r r
190deriving instance Show (EitherTag l r a)
191deriving instance Eq (EitherTag l r a)
192deriving instance Ord (EitherTag l r a)
194instance GEq (EitherTag l r) where
195 geq a b = case (a, b) of
196 (LeftTag, LeftTag) -> Just Refl
197 (RightTag, RightTag) -> Just Refl
200instance GCompare (EitherTag l r) where
201 gcompare a b = case (a, b) of
202 (LeftTag, LeftTag) -> GEQ
203 (LeftTag, RightTag) -> GLT
204 (RightTag, LeftTag) -> GGT
205 (RightTag, RightTag) -> GEQ
207instance GShow (EitherTag l r) where
208 gshowsPrec _ a = case a of
209 LeftTag -> showString "LeftTag"
210 RightTag -> showString "RightTag"
212-- | Convert 'Either' to a 'DSum'. Inverse of 'dsumToEither'.
213eitherToDSum :: Either a b -> DSum (EitherTag a b) Identity
215 Left a -> (LeftTag :=> Identity a)
216 Right b -> (RightTag :=> Identity b)
218-- | Convert 'DSum' to 'Either'. Inverse of 'eitherToDSum'.
219dsumToEither :: DSum (EitherTag a b) Identity -> Either a b
221 (LeftTag :=> Identity a) -> Left a
222 (RightTag :=> Identity b) -> Right b
224--------------------------------------------------------------------------------
226--------------------------------------------------------------------------------
228-- | We can't use @Compose Maybe@ instead of 'ComposeMaybe', because that would
229-- make the 'f' parameter have a nominal type role. We need f to be
230-- representational so that we can use safe 'coerce'.
231newtype ComposeMaybe f a =
232 ComposeMaybe { getComposeMaybe :: Maybe (f a) } deriving (Show, Eq, Ord)
234deriving 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