on master help sign in
Clean up positional lenses.
commit300f093215a3ce98d4f07b91f988ad329c050f3e authorWill Jones <will@sacharissa.co.uk> dateSun 30 Jul 2017, 12:46 (9 years ago) parentbc2c3be
5 files changed+189−9
generic-lens.cabal+1 src/Data/Generics/Internal/Families/Count.hs+5−5 src/Data/Generics/Product/Fields.hs+16−2 src/Data/Generics/Product/Numbered.hs+142 src/Data/Generics/Product/Typed.hs+25−2
generic-lens.cabal+1
@@ -34,6 +34,7 @@ cabal-version: >= 1.10
3434library
3535 exposed-modules: Data.Generics.Product
3636 , Data.Generics.Product.Fields
37+ , Data.Generics.Product.Numbered
3738 , Data.Generics.Product.Typed
3839
3940 , Data.Generics.Record
src/Data/Generics/Internal/Families/Count.hs+5−5
@@ -6,13 +6,13 @@
66
77module Data.Generics.Internal.Families.Count
88 ( CountType
9− , Counted (..)
9+ , Count (..)
1010 ) where
1111
1212import GHC.Generics
1313import GHC.TypeLits
1414
15−type family CountType t f :: Counted where
15+type family CountType t f :: Count where
1616 CountType t (S1 _ (Rec0 t))
1717 = 'One
1818 CountType t (l :*: r)
@@ -37,16 +37,16 @@ type family CountType t f :: Counted where
3737 ':<>: 'Text " is not a valid GHC.Generics representation type"
3838 )
3939
40−data Counted
40+data Count
4141 = None
4242 | One
4343 | Multiple
4444
45−type family (a :: Counted) <|> (b :: Counted) :: Counted where
45+type family (a :: Count) <|> (b :: Count) :: Count where
4646 'None <|> b = b
4747 a <|> 'None = a
4848 a <|> b = 'Multiple
4949
50−type family (a :: Counted) <&> (b :: Counted) :: Counted where
50+type family (a :: Count) <&> (b :: Count) :: Count where
5151 a <&> a = a
5252 _ <&> _ = 'Multiple
src/Data/Generics/Product/Fields.hs+16−2
@@ -19,7 +19,7 @@ module Data.Generics.Product.Fields
1919import Data.Generics.Internal.Families
2020import Data.Generics.Internal.Lens
2121
22−import Data.Kind (Type)
22+import Data.Kind (Constraint, Type)
2323import GHC.Generics
2424import GHC.TypeLits
2525
@@ -27,13 +27,27 @@ class HasField (field :: Symbol) a s | s field -> a where
2727 field :: Lens' s a
2828
2929instance (Generic s,
30− FindField field (Rep s) ~ 'Just a,
30+ found ~ FindField field (Rep s),
31+ ErrorUnlessJust field s found,
32+ found ~ 'Just a,
3133 GHasField field (Rep s) a)
3234
3335 => HasField field a s where
3436
3537 field = repIso . gfield @field
3638
39+type family ErrorUnlessJust (field :: Symbol) (s :: Type) (found :: Maybe Type) :: Constraint where
40+ ErrorUnlessJust field s 'Nothing
41+ = TypeError
42+ ( 'Text "The type "
43+ ':<>: 'ShowType s
44+ ':<>: 'Text " does not contain a field named "
45+ ':<>: 'ShowType field
46+ )
47+
48+ ErrorUnlessJust _ _ ('Just _)
49+ = ()
50+
3751class GHasField (field :: Symbol) (f :: Type -> Type) a | field f -> a where
3852 gfield :: Lens' (f x) a
3953
src/Data/Generics/Product/Numbered.hsnew file+142
@@ -0,0 +1,142 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE FunctionalDependencies #-}
5+{-# LANGUAGE KindSignatures #-}
6+{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE ScopedTypeVariables #-}
8+{-# LANGUAGE TypeApplications #-}
9+{-# LANGUAGE TypeFamilies #-}
10+{-# LANGUAGE TypeOperators #-}
11+{-# LANGUAGE UndecidableInstances #-}
12+
13+module Data.Generics.Product.Numbered
14+ ( HasPosition (..)
15+
16+ , GHasPosition (..)
17+ ) where
18+
19+import Data.Generics.Internal.Lens
20+
21+import Data.Kind (Constraint, Type)
22+import GHC.Generics
23+import GHC.TypeLits
24+
25+class HasPosition (i :: Nat) a s | s i -> a where
26+ numbered :: Lens' s a
27+
28+type BaseIndex
29+ = 1
30+
31+instance (Generic s,
32+ hasP ~ HasPositionP BaseIndex i (Rep s),
33+ ErrorUnlessTrue i s hasP,
34+ hasP ~ 'True,
35+ GHasPosition BaseIndex i (Rep s) a)
36+
37+ => HasPosition i a s where
38+
39+ numbered = repIso . gnumbered @BaseIndex @i
40+
41+type family ErrorUnlessTrue (i :: Nat) (s :: Type) (hasP :: Bool) :: Constraint where
42+ ErrorUnlessTrue i s 'False
43+ = TypeError
44+ ( 'Text "The type "
45+ ':<>: 'ShowType s
46+ ':<>: 'Text " does not contain a field at position "
47+ ':<>: 'ShowType i
48+ )
49+
50+ ErrorUnlessTrue _ _ 'True
51+ = ()
52+
53+class GHasPosition (offset :: Nat) (i :: Nat) (f :: Type -> Type) a | offset i f -> a where
54+ gnumbered :: Lens' (f x) a
55+
56+instance GHasPosition i i (S1 meta (Rec0 a)) a where
57+ gnumbered = mIso . gnumbered @i @i
58+
59+instance GHasPosition offset i (K1 R a) a where
60+ gnumbered f (K1 x) = fmap K1 (f x)
61+
62+instance GHasPosition offset i f a => GHasPosition offset i (M1 D meta f) a where
63+ gnumbered = mIso . gnumbered @offset @i
64+
65+instance GHasPosition offset i f a => GHasPosition offset i (M1 C meta f) a where
66+ gnumbered = mIso . gnumbered @offset @i
67+
68+instance (dir ~ ChooseDirection offset i l r,
69+ offset' ~ Offset dir offset (SizeOf l),
70+ GProductHasPosition offset' i l r a dir)
71+
72+ => GHasPosition offset i (l :*: r) a where
73+
74+ gnumbered = gproductNumbered @offset' @i @_ @_ @_ @dir
75+
76+class GProductHasPosition (offset :: Nat) (i :: Nat) l r a (dir :: Direction) | offset i l r dir -> a where
77+ gproductNumbered :: Lens' ((l :*: r) x) a
78+
79+instance GHasPosition offset i l a => GProductHasPosition offset i l r a 'GoLeft where
80+ gproductNumbered = first . gnumbered @offset @i
81+
82+instance GHasPosition offset i r a => GProductHasPosition offset i l r a 'GoRight where
83+ gproductNumbered = second . gnumbered @offset @i
84+
85+data Direction
86+ = GoLeft
87+ | GoRight
88+
89+type family ChooseDirection offset i l r :: Direction where
90+ ChooseDirection offset i l r
91+ = ChooseDirection' (HasPositionP offset i l) (HasPositionP (offset + SizeOf l) i r)
92+
93+type family ChooseDirection' (lHas :: Bool) (rHas :: Bool) :: Direction where
94+ ChooseDirection' 'True _
95+ = 'GoLeft
96+ ChooseDirection' _ 'True
97+ = 'GoRight
98+
99+type family HasPositionP (offset :: Nat) (i :: Nat) f :: Bool where
100+ HasPositionP offset i (D1 meta f)
101+ = HasPositionP offset i f
102+ HasPositionP n n (S1 _ _)
103+ = 'True
104+ HasPositionP _ _ (S1 _ _)
105+ = 'False
106+ HasPositionP offset i (l :*: r)
107+ = HasPositionP offset i l || HasPositionP (offset + SizeOf l) i r
108+ HasPositionP offset i (C1 meta f)
109+ = HasPositionP offset i f
110+ HasPositionP offset i (Rec0 _)
111+ = 'False
112+ HasPositionP offset i U1
113+ = 'False
114+ HasPositionP offset i V1
115+ = 'False
116+ HasPositionP offset i f
117+ = TypeError
118+ ( 'Text "Cannot determine if the type "
119+ ':<>: 'ShowType f
120+ ':<>: 'Text " has position "
121+ ':<>: 'ShowType i
122+ ':<>: 'Text " starting from offset "
123+ ':<>: 'ShowType offset
124+ )
125+
126+type family (x :: Bool) || (y :: Bool) :: Bool where
127+ 'True || _ = 'True
128+ _ || y = y
129+
130+type family SizeOf f :: Nat where
131+ SizeOf (l :*: r)
132+ = SizeOf l + SizeOf r
133+ SizeOf (D1 meta f)
134+ = SizeOf f
135+ SizeOf (C1 meta f)
136+ = SizeOf f
137+ SizeOf f
138+ = 1
139+
140+type family Offset (dir :: Direction) (offset :: Nat) (sizeOfLeft :: Nat) :: Nat where
141+ Offset 'GoLeft offset _ = offset
142+ Offset 'GoRight offset sl = offset + sl
src/Data/Generics/Product/Typed.hs+25−2
@@ -13,26 +13,49 @@
1313module Data.Generics.Product.Typed
1414 ( HasType (..)
1515
16+ , GHasType (..)
1617 ) where
1718
1819import Data.Generics.Internal.Families
1920import Data.Generics.Internal.Lens
2021
21−import Data.Kind (Type)
22+import Data.Kind (Constraint, Type)
2223import GHC.Generics
24+import GHC.TypeLits
2325
2426class HasType a s where
2527 typed :: Lens' s a
2628
2729instance (Generic s,
2830 FindType a (Rep s) ~ 'Just a,
29− CountType a (Rep s) ~ 'One,
31+ ErrorUnlessOne a s (CountType a (Rep s)),
3032 GHasType (Rep s) a)
3133
3234 => HasType a s where
3335
3436 typed = repIso . gtyped
3537
38+type family ErrorUnlessOne (a :: Type) (s :: Type) (count :: Count) :: Constraint where
39+ ErrorUnlessOne a s 'None
40+ = TypeError
41+ ( 'Text "The type "
42+ ':<>: 'ShowType s
43+ ':<>: 'Text " does not contain a value of type "
44+ ':<>: 'ShowType a
45+ )
46+
47+ ErrorUnlessOne a s 'Multiple
48+ = TypeError
49+ ( 'Text "The type "
50+ ':<>: 'ShowType s
51+ ':<>: 'Text " contains multiple values of type "
52+ ':<>: 'ShowType a
53+ ':<>: 'Text "; the choice of value is thus ambiguous"
54+ )
55+
56+ ErrorUnlessOne _ _ 'One
57+ = ()
58+
3659class GHasType (f :: Type -> Type) a where
3760 gtyped :: Lens' (f x) a
3861