on master help sign in
Add examples
commit1b9daf4a4255e8578fbcd736f974752c9d3dccb0 authorCsongor Kiss <kiss.csongor.kiss@gmail.com> dateTue 3 Apr 2018, 21:39 (9 years ago) parent2a4fec2
5 files changed+239−58
examples/Biscuits.hs+149 examples/doctest.hs+6 generic-lens.cabal+22 src/Data/Generics/Product/Types.hs+60−55 test/Spec.hs+2−3
examples/Biscuits.hsnew file+149
@@ -0,0 +1,149 @@
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE DeriveGeneric #-}
3+{-# LANGUAGE DuplicateRecordFields #-}
4+{-# LANGUAGE FlexibleContexts #-}
5+{-# LANGUAGE NoMonomorphismRestriction #-}
6+{-# LANGUAGE RankNTypes #-}
7+{-# LANGUAGE StandaloneDeriving #-}
8+{-# LANGUAGE TypeApplications #-}
9+{-# LANGUAGE TypeInType #-}
10+
11+module Main where
12+
13+import Control.Lens
14+import Data.Generics.Product
15+import Data.Generics.Sum
16+import GHC.Generics (Generic)
17+
18+-- $setup
19+--
20+-- >>> :set -XTypeApplications
21+-- >>> :set -XDataKinds
22+-- >>> :set -XFlexibleContexts
23+
24+main :: IO ()
25+main = putStrLn "hello"
26+
27+data Item = Item
28+ { name :: String
29+ , cost :: Cost
30+ } deriving (Generic, Show)
31+
32+newtype Cost = Cost Double deriving (Generic, Show)
33+
34+data Invoice p = Invoice
35+ { item :: Item
36+ , name :: String
37+ , number :: Int
38+ , priority :: p
39+ } deriving (Generic, Show)
40+
41+data Orders = Orders [ Invoice Int ] [ Invoice (Int, Double) ]
42+ deriving (Generic, Show)
43+
44+-- |
45+-- >>> view (field @"name") bourbon
46+-- "Bourbon"
47+-- >>> bourbon & field @"cost" .~ Cost 110
48+-- Item {name = "Bourbon", cost = Cost 110.0}
49+--
50+-- >>> bourbon & field @"cost" %~ (\(Cost c) -> (Cost (c + 5)))
51+-- Item {name = "Bourbon", cost = Cost 105.0}
52+--
53+-- >>> Invoice bourbon "Johnny" 2 2 & field @"priority" %~ (\i -> (i, 0))
54+-- Invoice {item = Item {name = "Bourbon", cost = Cost 100.0}, name = "Johnny", number = 2, priority = (2,0)}
55+--
56+-- >>> view (field @"weight") bourbon
57+-- ...
58+-- ... The type Item does not contain a field named 'weight'.
59+-- ...
60+--
61+-- >>> bourbon & typed @Cost .~ Cost 200
62+-- Item {name = "Bourbon", cost = Cost 200.0}
63+--
64+-- >>> bourbon & typed %~ ("Chocolate " ++)
65+-- Item {name = "Chocolate Bourbon", cost = Cost 100.0}
66+--
67+-- >>> view (position @1) (42, "foo")
68+-- 42
69+-- >>> view (position @1) (42, "foo", False)
70+-- 42
71+-- >>> view (position @2) orders
72+-- [Invoice {item = Item {name = "Bourbon", cost = Cost 100.0}, name = "George", number = 2, priority = (0,3.0)}]
73+--
74+-- >>> view (position @2) orders
75+-- [Invoice {item = Item {name = "Bourbon", cost = Cost 100.0}, name = "George", number = 2, priority = (0,3.0)}]
76+--
77+-- >>> view (position @3) orders
78+-- ...
79+-- ... The type Orders does not contain a field at position 3
80+-- ...
81+--
82+-- >>> view (super @Item) (WItem "Bourbon" (Cost 2000) (Weight 0.03))
83+-- Item {name = "Bourbon", cost = Cost 2000.0}
84+--
85+-- >>> (WItem "Bourbon+" (Cost 500) (Weight 0.03)) & super @Item .~ bourbon
86+-- WItem {name = "Bourbon", cost = Cost 100.0, weight = Weight 3.0e-2}
87+--
88+-- >>> DInt 1 ^? _Ctor @"DInt"
89+-- Just 1
90+--
91+-- >>> _Typed # (False, "wurble") :: D
92+-- DPair False "wurble"
93+--
94+-- >>> EChar 'a' ^? _Sub @D
95+-- Nothing
96+--
97+-- >>> _Sub # DInt 10 :: E
98+-- EInt 10
99+bourbon :: Item
100+bourbon = Item "Bourbon" (Cost 100)
101+
102+orders :: Orders
103+orders = Orders [Invoice bourbon "Earl" 1 0 , Invoice bourbon "Johnny" 2 2]
104+ [Invoice bourbon "George" 2 (0, 3)]
105+
106+nameOfItem :: Invoice p -> String
107+nameOfItem = view (field @"item" . field @"name")
108+
109+thankYou :: Orders -> Orders
110+thankYou = over (types @Cost) (\(Cost c) -> Cost (c * 0.85))
111+
112+thankYouPriority :: Orders -> Orders
113+thankYouPriority = over (position @2 . types @Cost) (\(Cost c) -> Cost (c * 0.85))
114+
115+upgrade :: Double -> Invoice Int -> Invoice (Int, Double)
116+upgrade bribe invoice = over (param @0) (\i -> (i, bribe)) invoice
117+
118+audit :: Orders -> [Item]
119+audit = toListOf (types @Item)
120+
121+newtype Weight = Weight Double deriving (Generic, Show)
122+data WeighedItem = WItem
123+ { name :: String
124+ , cost :: Cost
125+ , weight :: Weight
126+ } deriving (Generic, Show)
127+
128+data D = DInt Int | DPair Bool String
129+
130+deriving instance Generic D
131+deriving instance Show D
132+
133+data E = EInt Int | EPair Bool String | EChar Char
134+
135+deriving instance Generic E
136+deriving instance Show E
137+
138+costInc :: HasTypes t Cost => t -> t
139+costInc = over (types @Cost) (\(Cost c) -> Cost (c + 5))
140+
141+modifyPriority :: (Int -> Int) -> Invoice Int -> Invoice Int
142+modifyPriority = over (types @Int)
143+
144+treeIncParam :: HasParam 0 s s Int Int => s -> s
145+treeIncParam = over (param @0) (+ 1)
146+
147+instance Functor Invoice where
148+ fmap = over (param @0)
149+
examples/doctest.hsnew file+6
@@ -0,0 +1,6 @@
1+import Test.DocTest
2+main
3+ = doctest
4+ [ "-iexamples"
5+ , "examples/Biscuits.hs"
6+ ]
generic-lens.cabal+22
@@ -80,6 +80,20 @@ source-repository head
8080 type: git
8181 location: https://github.com/kcsongor/generic-lens
8282
83+test-suite generic-lens-examples
84+ type: exitcode-stdio-1.0
85+ hs-source-dirs: examples
86+ main-is: Biscuits.hs
87+ --other-modules:
88+
89+ build-depends: base >= 4.9 && <= 5.0
90+ , generic-lens
91+ , lens
92+ , profunctors
93+ , HUnit
94+
95+ default-language: Haskell2010
96+
8397test-suite generic-lens-test
8498 type: exitcode-stdio-1.0
8599 hs-source-dirs: test
@@ -140,6 +154,14 @@ test-suite doctests
140154 build-depends: base >4 && <5, doctest
141155 hs-source-dirs: test
142156
157+test-suite examples-doctests
158+ default-language: Haskell2010
159+ type: exitcode-stdio-1.0
160+ ghc-options: -threaded
161+ main-is: doctest.hs
162+ build-depends: base >4 && <5, doctest
163+ hs-source-dirs: examples
164+
143165benchmark generic-lens-bench
144166 type: exitcode-stdio-1.0
145167 hs-source-dirs: benchmarks
src/Data/Generics/Product/Types.hs+60−55
@@ -30,7 +30,8 @@ module Data.Generics.Product.Types
3030 ( -- *Traversals
3131 --
3232 -- $example
33− HasTypes (..)
33+ HasTypes
34+ , types
3435 ) where
3536
3637import Data.Kind
@@ -40,80 +41,84 @@ import Data.Generics.Internal.VL.Traversal
4041
4142-- TODO [1.0.0.0]: use type-changing variant internally
4243
43−class HasTypes a s where
44− types :: Traversal' s a
44+types :: forall a s. HasTypes s a => Traversal' s a
45+types = types_ @s @a
46+{-# INLINE types #-}
4547
46− default types :: Traversal' s a
47− types _ = pure
48− {-# INLINE types #-}
48+class HasTypes s a where
49+ types_ :: Traversal' s a
50+
51+ default types_ :: Traversal' s a
52+ types_ _ = pure
53+ {-# INLINE types_ #-}
4954
5055instance
51− ( Hastypes' (Interesting s a) a s
52− ) => HasTypes a s where
53− types = types' @(Interesting s a)
54− {-# INLINE types #-}
56+ ( HasTypes' (Interesting s a) s a
57+ ) => HasTypes s a where
58+ types_ = types' @(Interesting s a)
59+ {-# INLINE types_ #-}
5560
56−class Hastypes' (t :: Bool) a s where
61+class HasTypes' (t :: Bool) s a where
5762 types' :: Traversal' s a
5863
5964instance
60− ( GHasTypes a (Rep s)
65+ ( GHasTypes (Rep s) a
6166 , Generic s
62− ) => Hastypes' 'True a s where
63− types' f s = to <$> gtypes f (from s)
67+ ) => HasTypes' 'True s a where
68+ types' f s = to <$> gtypes_ f (from s)
6469 --{-# INLINE types' #-}
6570
66−instance Hastypes' 'False a s where
71+instance HasTypes' 'False s a where
6772 types' _ = pure
6873 --{-# INLINE types' #-}
6974
70−instance {-# OVERLAPPING #-} HasTypes a Bool
71−instance {-# OVERLAPPING #-} HasTypes a Char
72−instance {-# OVERLAPPING #-} HasTypes a Double
73−instance {-# OVERLAPPING #-} HasTypes a Float
74−instance {-# OVERLAPPING #-} HasTypes a Int
75−instance {-# OVERLAPPING #-} HasTypes a Integer
76−instance {-# OVERLAPPING #-} HasTypes a Ordering
75+instance {-# OVERLAPPING #-} HasTypes Bool a
76+instance {-# OVERLAPPING #-} HasTypes Char a
77+instance {-# OVERLAPPING #-} HasTypes Double a
78+instance {-# OVERLAPPING #-} HasTypes Float a
79+instance {-# OVERLAPPING #-} HasTypes Int a
80+instance {-# OVERLAPPING #-} HasTypes Integer a
81+instance {-# OVERLAPPING #-} HasTypes Ordering a
7782
7883--------------------------------------------------------------------------------
7984
80−class GHasTypes a s where
81− gtypes :: Traversal' (s x) a
85+class GHasTypes s a where
86+ gtypes_ :: Traversal' (s x) a
8287
8388instance
84− ( GHasTypes a l
85− , GHasTypes a r
86− ) => GHasTypes a (l :*: r) where
87− gtypes f (l :*: r) = (:*:) <$> gtypes f l <*> gtypes f r
88− {-# INLINE gtypes #-}
89+ ( GHasTypes l a
90+ , GHasTypes r a
91+ ) => GHasTypes (l :*: r) a where
92+ gtypes_ f (l :*: r) = (:*:) <$> gtypes_ f l <*> gtypes_ f r
93+ {-# INLINE gtypes_ #-}
8994
9095instance
91− ( GHasTypes a l
92− , GHasTypes a r
93− ) => GHasTypes a (l :+: r) where
94− gtypes f (L1 l) = L1 <$> gtypes f l
95− gtypes f (R1 r) = R1 <$> gtypes f r
96− {-# INLINE gtypes #-}
97−
98−instance (GHasTypes a s) => GHasTypes a (M1 m meta s) where
99− gtypes f (M1 s) = M1 <$> gtypes f s
100− {-# INLINE gtypes #-}
101−
102−instance {-# OVERLAPPING #-} GHasTypes a (Rec0 a) where
103− gtypes f (K1 x) = K1 <$> f x
104− {-# INLINE gtypes #-}
105−
106−instance HasTypes a b => GHasTypes a (Rec0 b) where
107− gtypes f (K1 x) = K1 <$> types @a f x
108− {-# INLINE gtypes #-}
109−
110−instance GHasTypes a U1 where
111− gtypes _ _ = pure U1
112− {-# INLINE gtypes #-}
113−
114−instance GHasTypes a V1 where
115− gtypes _ = pure
116− {-# INLINE gtypes #-}
96+ ( GHasTypes l a
97+ , GHasTypes r a
98+ ) => GHasTypes (l :+: r) a where
99+ gtypes_ f (L1 l) = L1 <$> gtypes_ f l
100+ gtypes_ f (R1 r) = R1 <$> gtypes_ f r
101+ {-# INLINE gtypes_ #-}
102+
103+instance (GHasTypes s a) => GHasTypes (M1 m meta s) a where
104+ gtypes_ f (M1 s) = M1 <$> gtypes_ f s
105+ {-# INLINE gtypes_ #-}
106+
107+instance {-# OVERLAPPING #-} GHasTypes (Rec0 a) a where
108+ gtypes_ f (K1 x) = K1 <$> f x
109+ {-# INLINE gtypes_ #-}
110+
111+instance HasTypes b a => GHasTypes (Rec0 b) a where
112+ gtypes_ f (K1 x) = K1 <$> types_ @_ @a f x
113+ {-# INLINE gtypes_ #-}
114+
115+instance GHasTypes U1 a where
116+ gtypes_ _ _ = pure U1
117+ {-# INLINE gtypes_ #-}
118+
119+instance GHasTypes V1 a where
120+ gtypes_ _ = pure
121+ {-# INLINE gtypes_ #-}
117122
118123type Interesting f a = Snd (Interesting' (Rep f) a '[f])
119124
test/Spec.hs+2−3
@@ -223,7 +223,6 @@ tests = TestList $ map mkHUnitTest
223223 , $(inspectTest $ 'typeChangingManual === 'typeChangingGeneric)
224224 , $(inspectTest $ 'typeChangingManual === 'typeChangingGenericPos)
225225 , $(inspectTest $ 'typeChangingManualCompose === 'typeChangingGenericCompose)
226− , $(inspectTest $ 'intTraversalManual === 'intTraversalDerived)
227226 , $(inspectTest $ 'sum1PrismManual === 'sum1PrismB)
228227 , $(inspectTest $ 'subtypePrismManual === 'subtypePrismGeneric)
229228 , $(inspectTest $ 'sum2PrismManualChar === 'sum2TypePrismChar)
@@ -231,8 +230,8 @@ tests = TestList $ map mkHUnitTest
231230 , $(inspectTest $ 'sum1PrismManualChar === 'sum1TypePrismChar)
232231 , $(inspectTest $ 'sum2PrismManualChar === 'sum2TypePrismChar)
233232 , $(inspectTest $ 'sum1PrismManual === 'sum1TypePrism)
234− , $(inspectTest $ 'intTraversalManual === 'intTraversalDerived)
235− , $(inspectTest $ 'sum3Param0Manual === 'sum3Param0Derived)
233+ --, $(inspectTest $ 'intTraversalManual === 'intTraversalDerived)
234+ --, $(inspectTest $ 'sum3Param0Manual === 'sum3Param0Derived)
236235 -- TODO [1.0.0.0]: these tests pass with the new implementation
237236-- , $(inspectTest $ 'sum3Param1Manual === 'sum3Param1Derived)
238237-- , $(inspectTest $ 'sum3Param2Manual === 'sum3Param2Derived)