@@ -4,6 +4,7 @@
4{-# LANGUAGE FunctionalDependencies #-}
4{-# LANGUAGE FunctionalDependencies #-}
5{-# LANGUAGE KindSignatures #-}
5{-# LANGUAGE KindSignatures #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE PolyKinds #-}
7{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE TypeApplications #-}
9{-# LANGUAGE TypeApplications #-}
9{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE TypeFamilies #-}
@@ -12,7 +13,7 @@
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
15−-- Module : Data.Generics.Record.HasField
16+-- Module : Data.Generics.Product.Positions
16-- Copyright : (C) 2017 Csongor Kiss
17-- Copyright : (C) 2017 Csongor Kiss
17-- License : BSD3
18-- License : BSD3
18-- Maintainer : Csongor Kiss <kiss.csongor.kiss@gmail.com>
19-- Maintainer : Csongor Kiss <kiss.csongor.kiss@gmail.com>
@@ -23,7 +24,7 @@
24-----------------------------------------------------------------------------
25-----------------------------------------------------------------------------
26−module Data.Generics.Product.Numbered
27+module Data.Generics.Product.Positions
27 ( -- *Lenses
28 ( -- *Lenses
29 -- $example
30 -- $example
@@ -64,37 +65,33 @@ import GHC.TypeLits
64-- >>> getPosition @1 human
65-- >>> getPosition @1 human
65-- "Tunyasz"
66-- "Tunyasz"
66getPosition :: forall i a s. HasPosition i a s => s -> a
67getPosition :: forall i a s. HasPosition i a s => s -> a
67−getPosition s = s ^. numbered @i
68+getPosition s = s ^. position @i
69-- | Set positional field
70-- | Set positional field
71-- >>> setPosition @2 (setField @1 "Tamas" human) 30
72-- >>> setPosition @2 (setField @1 "Tamas" human) 30
72-- Human "Tamas" 30 "London"
73-- Human "Tamas" 30 "London"
73setPosition :: forall i a s. HasPosition i a s => a -> s -> s
74setPosition :: forall i a s. HasPosition i a s => a -> s -> s
74−setPosition = set (numbered @i)
75+setPosition = set (position @i)
76-- |Records that have a field at a given position.
77-- |Records that have a field at a given position.
77class HasPosition (i :: Nat) a s | s i -> a where
78class HasPosition (i :: Nat) a s | s i -> a where
78 -- |A lens that focuses on a field at a given position. Compatible with the
79 -- |A lens that focuses on a field at a given position. Compatible with the
79 -- lens package's 'Control.Lens.Lens' type.
80 -- lens package's 'Control.Lens.Lens' type.
81− -- >>> human ^. numbered @1
82+ -- >>> human ^. position @1
82 -- "Tunyasz"
83 -- "Tunyasz"
83− -- >>> human & numbered @2 .~ "Berlin"
84+ -- >>> human & position @2 .~ "Berlin"
84 -- Human {name = "Tunyasz", age = 50, address = "Berlin"}
85 -- Human {name = "Tunyasz", age = 50, address = "Berlin"}
85− numbered :: Lens' s a
86+ position :: Lens' s a
87−-- |The base index from which positions are counted.
92 ( Generic s
89 ( Generic s
93− , ErrorUnlessTrue i s (HasPositionP BaseIndex i (Rep s))
90+ , ErrorUnlessTrue i s (0 <? i && i <=? Size (Rep s))
94− , GHasPosition BaseIndex i (Rep s) a
91+ , GHasPosition 1 i (Rep s) a
95 ) => HasPosition i a s where
92 ) => HasPosition i a s where
97− numbered = repIso . gnumbered @BaseIndex @i
94+ position = repIso . gposition @1 @i
99type family ErrorUnlessTrue (i :: Nat) (s :: Type) (hasP :: Bool) :: Constraint where
96type family ErrorUnlessTrue (i :: Nat) (s :: Type) (hasP :: Bool) :: Constraint where
100 ErrorUnlessTrue i s 'False
97 ErrorUnlessTrue i s 'False
@@ -111,92 +108,70 @@ type family ErrorUnlessTrue (i :: Nat) (s :: Type) (hasP :: Bool) :: Constraint
111-- |As 'HasPosition' but over generic representations as defined by
108-- |As 'HasPosition' but over generic representations as defined by
112-- "GHC.Generics".
109-- "GHC.Generics".
113class GHasPosition (offset :: Nat) (i :: Nat) (f :: Type -> Type) a | offset i f -> a where
110class GHasPosition (offset :: Nat) (i :: Nat) (f :: Type -> Type) a | offset i f -> a where
114− gnumbered :: Lens' (f x) a
111+ gposition :: Lens' (f x) a
116instance GHasPosition i i (S1 meta (Rec0 a)) a where
113instance GHasPosition i i (S1 meta (Rec0 a)) a where
117− gnumbered = mIso . gnumbered @i @i
114+ gposition = mIso . gposition @i @i
119instance GHasPosition offset i (K1 R a) a where
116instance GHasPosition offset i (K1 R a) a where
120− gnumbered f (K1 x) = fmap K1 (f x)
117+ gposition f (K1 x) = fmap K1 (f x)
122instance GHasPosition offset i f a => GHasPosition offset i (M1 D meta f) a where
119instance GHasPosition offset i f a => GHasPosition offset i (M1 D meta f) a where
123− gnumbered = mIso . gnumbered @offset @i
120+ gposition = mIso . gposition @offset @i
125instance GHasPosition offset i f a => GHasPosition offset i (M1 C meta f) a where
122instance GHasPosition offset i f a => GHasPosition offset i (M1 C meta f) a where
126− gnumbered = mIso . gnumbered @offset @i
123+ gposition = mIso . gposition @offset @i
128−instance (dir ~ ChooseDirection offset i l r,
125+instance
126+ ( goLeft ~ (i <? (offset + Size l))
129− offset' ~ Offset dir offset (SizeOf l),
127+ , offset' ~ (If goLeft offset (offset + Size l))
130− GProductHasPosition offset' i l r a dir)
128+ , GProductHasPosition offset' i l r a goLeft
132− => GHasPosition offset i (l :*: r) a where
129+ ) => GHasPosition offset i (l :*: r) a where
134− gnumbered = gproductNumbered @offset' @i @_ @_ @_ @dir
131+ gposition = gproductPosition @offset' @i @_ @_ @_ @goLeft
136−class GProductHasPosition (offset :: Nat) (i :: Nat) l r a (dir :: Direction) | offset i l r dir -> a where
134+class GProductHasPosition (offset :: Nat) (i :: Nat) l r a (left :: Bool) | offset i l r left -> a where
137− gproductNumbered :: Lens' ((l :*: r) x) a
135+ gproductPosition :: Lens' ((l :*: r) x) a
139−instance GHasPosition offset i l a => GProductHasPosition offset i l r a 'GoLeft where
140− gproductNumbered = first . gnumbered @offset @i
142−instance GHasPosition offset i r a => GProductHasPosition offset i l r a 'GoRight where
143− gproductNumbered = second . gnumbered @offset @i
149−type family ChooseDirection offset i l r :: Direction where
150− ChooseDirection offset i l r
151− = ChooseDirection' (HasPositionP offset i l) (HasPositionP (offset + SizeOf l) i r)
153−type family ChooseDirection' (lHas :: Bool) (rHas :: Bool) :: Direction where
154− ChooseDirection' 'True _
156− ChooseDirection' _ 'True
159−type family HasPositionP (offset :: Nat) (i :: Nat) f :: Bool where
160− HasPositionP offset i (D1 meta f)
161− = HasPositionP offset i f
162− HasPositionP n n (S1 _ _)
164− HasPositionP _ _ (S1 _ _)
166− HasPositionP offset i (l :*: r)
167− = HasPositionP offset i l || HasPositionP (offset + SizeOf l) i r
168− HasPositionP offset i (C1 meta f)
169− = HasPositionP offset i f
170− HasPositionP offset i (Rec0 _)
172− HasPositionP offset i U1
174− HasPositionP offset i V1
176− HasPositionP offset i f
178− ( 'Text "Cannot determine if the type "
180− ':<>: 'Text " has position "
182− ':<>: 'Text " starting from offset "
183− ':<>: 'ShowType offset
186−type family (x :: Bool) || (y :: Bool) :: Bool where
137+instance GHasPosition offset i l a => GProductHasPosition offset i l r a 'True where
187− 'True || _ = 'True
138+ gproductPosition = first . gposition @offset @i
189−
140+instance GHasPosition offset i r a => GProductHasPosition offset i l r a 'False where
141+ gproductPosition = second . gposition @offset @i
190−type family SizeOf f :: Nat where
143+type family Size f :: Nat where
191− SizeOf (l :*: r)
144+ Size (l :*: r)
192− = SizeOf l + SizeOf r
145+ = Size l + Size r
193− SizeOf (D1 meta f)
148+ Size (D1 meta f)
194− = SizeOf f
149+ = Size f
195− SizeOf (C1 meta f)
150+ Size (C1 meta f)
196− = SizeOf f
151+ = Size f
200−type family Offset (dir :: Direction) (offset :: Nat) (sizeOfLeft :: Nat) :: Nat where
155+--------------------------------------------------------------------------------
201− Offset 'GoLeft offset _ = offset
156+
202− Offset 'GoRight offset sl = offset + sl
157+type family Not (b :: Bool) where
161+type family (<?) (x :: Nat) (y :: Nat) :: Bool where
162+ x <? y = Not (y <=? x)
166+type family If (c :: Bool) (x :: k) (y :: k) :: k where
170+type family Min (a :: Nat) (b :: Nat) :: Nat where
171+ Min a b = If (a <? b) a b
173+type family (a :: Bool) && (b :: Bool) :: Bool where
174+ 'True && 'True = 'True