@@ -0,0 +1,99 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE ConstraintKinds #-}
3+{-# LANGUAGE DataKinds #-}
4+{-# LANGUAGE FlexibleContexts #-}
5+{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE FunctionalDependencies #-}
8+{-# LANGUAGE Rank2Types #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE TypeApplications #-}
11+{-# LANGUAGE TypeFamilyDependencies #-}
12+{-# LANGUAGE TypeOperators #-}
13+{-# LANGUAGE UndecidableInstances #-}
15+-----------------------------------------------------------------------------
17+-- Module : Data.Generics.Product.Internal.Constraints
18+-- Copyright : (C) 2017 Csongor Kiss
20+-- Maintainer : Csongor Kiss <kiss.csongor.kiss@gmail.com>
21+-- Stability : experimental
22+-- Portability : non-portable
24+-- Derive constrained traversals
26+-----------------------------------------------------------------------------
28+-- TODO: use type-changing variant
30+module Data.Generics.Product.Internal.Constraints
36+import Data.Kind (Type, Constraint)
38+import Data.Generics.Internal.VL.Iso
40+-- | Constrained traversal.
41+class GHasConstraints (c :: * -> Constraint) (f :: * -> *) where
42+ gconstraints :: forall g x.
43+ Applicative g => (forall a. c a => a -> g a) -> f x -> g (f x)
45+instance (GHasConstraints c l, GHasConstraints c r) => GHasConstraints c (l :*: r) where
46+ gconstraints f (l :*: r) = (:*:) <$> gconstraints @c f l <*> gconstraints @c f r
48+instance (GHasConstraints c l, GHasConstraints c r) => GHasConstraints c (l :+: r) where
49+ gconstraints f (L1 l) = L1 <$> gconstraints @c f l
50+ gconstraints f (R1 r) = R1 <$> gconstraints @c f r
52+instance c a => GHasConstraints c (K1 R a) where
55+instance GHasConstraints c f => GHasConstraints c (M1 m meta f) where
56+ gconstraints f (M1 x) = M1 <$> gconstraints @c f x
58+instance GHasConstraints c U1 where
59+ gconstraints _ _ = pure U1
61+--------------------------------------------------------------------------------
64+--type GHasTypes rep as = GHasConstraints (Contains as) rep
66+-- Try to use a function from the list, or default to 'pure' if not present
72+ ) => HList (Functions as g) -> f x -> g (f x)
73+gtypes hl s = gconstraints @(Contains as) (pick hl) s
76+--------------------------------------------------------------------------------
78+data HList (ts :: [Type]) where
80+ (:>) :: a -> HList as -> HList (a ': as)
83+-- >>> :kind! Functions '[Int, Char, Bool] Maybe
84+-- '[Int -> Maybe Int, Char -> Maybe Char, Bool -> Maybe Bool]
85+type family Functions (ts :: [Type]) (g :: Type -> Type) = r | r -> ts where
86+ Functions '[] _ = '[]
87+ Functions (t ': ts) g = ((t -> g t) ': Functions ts g)
89+class Contains as a where
90+ pick :: Applicative g => HList (Functions as g) -> a -> g a
92+instance {-# OVERLAPPING #-} Contains (a ': as) a where
95+instance Contains as a => Contains (b ': as) a where
96+ pick (_ :> hs) = pick hs
98+instance Contains '[] a where