···11# Let's Lens
22+33+
44+55+66+### Abstract
77+88+Let's Lens presents a series of exercises, in a similar format to
99+[the NICTA functional programming course material](http://github.com/NICTA/course).
1010+The subject of the exercises is around the concept of lenses, initially proposed
1111+by Foster et al., to solve the view-update problem of relational databases.
1212+1313+The theories around lenses have been advanced significantly in recent years,
1414+resulting in a library, implemented in Haskell, called `lens`.
1515+1616+http://hackage.haskell.org/package/lens
1717+1818+The exercises take into account various possible goals. For example, if you wish
1919+to study the history of lenses, then build up to the most recent theories, it is
2020+best to start at the `Lets.GetSetLens` module. If you wish to derive the
2121+structure of lenses from first principles, then derive the more modern theories,
2222+start at the `Lets.Lens.Lens` module.
2323+2424+----
2525+2626+### Exercise modules
2727+2828+##### `Lets.GetSetLens`
2929+3030+This module presents a series of exercises, representing lenses as a traditional
3131+pair of "`get` and `set`" functions. This representation may be beneficial as it
3232+easily appeals to an intuition of "what a lens is", however, it is outdated.
3333+3434+These exercises are useful to gain an initial understanding of the problems that
3535+lenses solve, as well as to gain an insight into the history of lenses and how
3636+the theories have developed over time.
3737+3838+##### `Lets.StoreLens`
3939+4040+This series of exercises is similar to `Lets.GetSetLens`, however, using a
4141+slightly altered representation of a lens, based on the `Store` comonad, which
4242+fuses the typical `get` and `set` operations into a data structure. This
4343+representation is described in detail in
4444+*Morris, Tony. "Asymmetric Lenses in Scala." (2012).*
4545+4646+##### `Lets.OpticPolyLens`
4747+4848+This series of exercises introduces a new representation of lenses, first
4949+described by Twan van Laarhoven. This representation also introduces a
5050+generalisation of lenses to permit *polymorphic update* of structures.
5151+5252+##### `Lets.Lens.Lens`
5353+5454+This series of exercises starts at first principles to derive the concept of a
5555+lens, as it was first described by Twan van Laarhoven. The derivation then goes
5656+on to described other structures to solve various practical problems such as
5757+*multi-update* and *partial update*.
5858+5959+This representation presents a generalisation, permitting *polymorphic update*
6060+over structures. After lenses are derived, further concepts are introduced, such
6161+as `Fold`s, `Traversal`s and `Prism`s.
6262+6363+----
6464+6565+### Credits
6666+6767+* Edward Kmett on the [derivation of lenses](https://github.com/ekmett/lens/wiki/Derivation)
···11-module Lets where
11+module Lets (
22+ module L
33+) where
2455+import Lets.Data as L
66+import Lets.GetSetLens as L()
77+import Lets.Lens as L()
88+import Lets.OpticPolyLens as L()
99+import Lets.StoreLens as L()
+180
src/Lets/Data.hs
···11+module Lets.Data (
22+ Locality(..)
33+, Address(..)
44+, Person(..)
55+, IntAnd(..)
66+, IntOr(..)
77+, fredLocality
88+, fredAddress
99+, fred
1010+, maryLocality
1111+, maryAddress
1212+, mary
1313+, Store(..)
1414+, Const (..)
1515+, Tagged(..)
1616+, Identity(..)
1717+, AlongsideLeft(..)
1818+, AlongsideRight(..)
1919+) where
2020+2121+import Control.Applicative(Applicative(..))
2222+import Data.Monoid(Monoid(..))
2323+2424+data Locality =
2525+ Locality
2626+ String -- city
2727+ String -- state
2828+ String -- country
2929+ deriving (Eq, Show)
3030+3131+data Address =
3232+ Address
3333+ String -- street
3434+ String -- suburb
3535+ Locality
3636+ deriving (Eq, Show)
3737+3838+data Person =
3939+ Person
4040+ Int -- age
4141+ String -- name
4242+ Address -- address
4343+ deriving (Eq, Show)
4444+4545+data IntAnd a =
4646+ IntAnd
4747+ Int
4848+ a
4949+ deriving (Eq, Show)
5050+5151+data IntOr a =
5252+ IntOrIs Int
5353+ | IntOrIsNot a
5454+ deriving (Eq, Show)
5555+5656+fredLocality ::
5757+ Locality
5858+fredLocality =
5959+ Locality
6060+ "Fredmania"
6161+ "New South Fred"
6262+ "Fredalia"
6363+6464+fredAddress ::
6565+ Address
6666+fredAddress =
6767+ Address
6868+ "15 Fred St"
6969+ "Fredville"
7070+ fredLocality
7171+7272+fred ::
7373+ Person
7474+fred =
7575+ Person
7676+ 24
7777+ "Fred"
7878+ fredAddress
7979+8080+maryLocality ::
8181+ Locality
8282+maryLocality =
8383+ Locality
8484+ "Mary Mary"
8585+ "Western Mary"
8686+ "Maristan"
8787+8888+maryAddress ::
8989+ Address
9090+maryAddress =
9191+ Address
9292+ "83 Mary Ln"
9393+ "Maryland"
9494+ maryLocality
9595+9696+mary ::
9797+ Person
9898+mary =
9999+ Person
100100+ 28
101101+ "Mary"
102102+ maryAddress
103103+104104+----
105105+106106+data Store s a =
107107+ Store
108108+ (s -> a)
109109+ s
110110+111111+data Const a b =
112112+ Const {
113113+ getConst ::
114114+ a
115115+ }
116116+ deriving (Eq, Show)
117117+118118+instance Functor (Const a) where
119119+ fmap _ (Const a) =
120120+ Const a
121121+122122+instance Monoid a => Applicative (Const a) where
123123+ pure _ =
124124+ Const mempty
125125+ Const f <*> Const a =
126126+ Const (f `mappend` a)
127127+128128+data Tagged a b =
129129+ Tagged {
130130+ getTagged ::
131131+ b
132132+ }
133133+ deriving (Eq, Show)
134134+135135+instance Functor (Tagged a) where
136136+ fmap f (Tagged b) =
137137+ Tagged (f b)
138138+139139+instance Applicative (Tagged a) where
140140+ pure =
141141+ Tagged
142142+ Tagged f <*> Tagged a =
143143+ Tagged (f a)
144144+145145+data Identity a =
146146+ Identity {
147147+ getIdentity ::
148148+ a
149149+ }
150150+ deriving (Eq, Show)
151151+152152+instance Functor Identity where
153153+ fmap f (Identity a) =
154154+ Identity (f a)
155155+156156+instance Applicative Identity where
157157+ pure =
158158+ Identity
159159+ Identity f <*> Identity a =
160160+ Identity (f a)
161161+162162+data AlongsideLeft f b a =
163163+ AlongsideLeft {
164164+ getAlongsideLeft ::
165165+ f (a, b)
166166+ }
167167+168168+instance Functor f => Functor (AlongsideLeft f b) where
169169+ fmap f (AlongsideLeft x) =
170170+ AlongsideLeft (fmap (\(a, b) -> (f a, b)) x)
171171+172172+data AlongsideRight f a b =
173173+ AlongsideRight {
174174+ getAlongsideRight ::
175175+ f (a, b)
176176+ }
177177+178178+instance Functor f => Functor (AlongsideRight f a) where
179179+ fmap f (AlongsideRight x) =
180180+ AlongsideRight (fmap (\(a, b) -> (a, f b)) x)
+544
src/Lets/GetSetLens.hs
···11+module Lets.GetSetLens (
22+ Lens(..)
33+, getsetLaw
44+, setgetLaw
55+, setsetLaw
66+, get
77+, set
88+, modify
99+, (%~)
1010+, fmodify
1111+, (|=)
1212+, fstL
1313+, sndL
1414+, mapL
1515+, setL
1616+, compose
1717+, (|.)
1818+, identity
1919+, product
2020+, (***)
2121+, choice
2222+, (|||)
2323+, cityL
2424+, countryL
2525+, streetL
2626+, suburbL
2727+, localityL
2828+, ageL
2929+, nameL
3030+, addressL
3131+, getSuburb
3232+, setStreet
3333+, getAgeAndCountry
3434+, setCityAndLocality
3535+, getSuburbOrCity
3636+, setStreetOrState
3737+, modifyCityUppercase
3838+) where
3939+4040+import Control.Applicative((<*>))
4141+import Data.Bool(bool)
4242+import Data.Char(toUpper)
4343+import Data.Map(Map)
4444+import qualified Data.Map as Map(insert, delete, lookup)
4545+import Data.Set(Set)
4646+import qualified Data.Set as Set(insert, delete, member)
4747+import Lets.Data
4848+import Prelude hiding (product)
4949+5050+-- $setup
5151+-- >>> import qualified Data.Map as Map(fromList)
5252+-- >>> import qualified Data.Set as Set(fromList)
5353+-- >>> import Data.Char(ord)
5454+5555+data Lens a b =
5656+ Lens
5757+ (a -> b -> a)
5858+ (a -> b)
5959+6060+-- |
6161+--
6262+-- >>> get fstL (0 :: Int, "abc")
6363+-- 0
6464+--
6565+-- >>> get sndL ("abc", 0 :: Int)
6666+-- 0
6767+--
6868+-- prop> let types = (x :: Int, y :: String) in get fstL (x, y) == x
6969+--
7070+-- prop> let types = (x :: Int, y :: String) in get sndL (x, y) == y
7171+get ::
7272+ Lens a b
7373+ -> a
7474+ -> b
7575+get (Lens _ g) =
7676+ g
7777+7878+-- |
7979+--
8080+-- >>> set fstL (0 :: Int, "abc") 1
8181+-- (1,"abc")
8282+--
8383+-- >>> set sndL ("abc", 0 :: Int) 1
8484+-- ("abc",1)
8585+--
8686+-- prop> let types = (x :: Int, y :: String) in set fstL (x, y) z == (z, y)
8787+--
8888+-- prop> let types = (x :: Int, y :: String) in set sndL (x, y) z == (x, z)
8989+set ::
9090+ Lens a b
9191+ -> a
9292+ -> b
9393+ -> a
9494+set (Lens s _) a =
9595+ s a
9696+9797+-- | The get/set law of lenses. This function should always return @True@.
9898+getsetLaw ::
9999+ Eq a =>
100100+ Lens a b
101101+ -> a
102102+ -> Bool
103103+getsetLaw l =
104104+ \a -> set l a (get l a) == a
105105+106106+-- | The set/get law of lenses. This function should always return @True@.
107107+setgetLaw ::
108108+ Eq b =>
109109+ Lens a b
110110+ -> a
111111+ -> b
112112+ -> Bool
113113+setgetLaw l a b =
114114+ get l (set l a b) == b
115115+116116+-- | The set/set law of lenses. This function should always return @True@.
117117+setsetLaw ::
118118+ Eq a =>
119119+ Lens a b
120120+ -> a
121121+ -> b
122122+ -> b
123123+ -> Bool
124124+setsetLaw l a b1 b2 =
125125+ set l (set l a b1) b2 == set l a b2
126126+127127+----
128128+129129+-- |
130130+--
131131+-- >>> modify fstL (+1) (0 :: Int, "abc")
132132+-- (1,"abc")
133133+--
134134+-- >>> modify sndL (+1) ("abc", 0 :: Int)
135135+-- ("abc",1)
136136+--
137137+-- prop> let types = (x :: Int, y :: String) in modify fstL id (x, y) == (x, y)
138138+--
139139+-- prop> let types = (x :: Int, y :: String) in modify sndL id (x, y) == (x, y)
140140+modify ::
141141+ Lens a b
142142+ -> (b -> b)
143143+ -> a
144144+ -> a
145145+modify =
146146+ error "todo: modify"
147147+148148+-- | An alias for @modify@.
149149+(%~) ::
150150+ Lens a b
151151+ -> (b -> b)
152152+ -> a
153153+ -> a
154154+(%~) =
155155+ modify
156156+157157+infixr 4 %~
158158+159159+-- |
160160+--
161161+-- >>> fstL .~ 1 $ (0 :: Int, "abc")
162162+-- (1,"abc")
163163+--
164164+-- >>> sndL .~ 1 $ ("abc", 0 :: Int)
165165+-- ("abc",1)
166166+--
167167+-- prop> let types = (x :: Int, y :: String) in set fstL (x, y) z == (fstL .~ z $ (x, y))
168168+--
169169+-- prop> let types = (x :: Int, y :: String) in set sndL (x, y) z == (sndL .~ z $ (x, y))
170170+(.~) ::
171171+ Lens a b
172172+ -> b
173173+ -> a
174174+ -> a
175175+(.~) =
176176+ error "todo: (.~)"
177177+178178+infixl 5 .~
179179+180180+-- |
181181+--
182182+-- >>> fmodify fstL (+) (5 :: Int, "abc") 8
183183+-- (13,"abc")
184184+--
185185+-- >>> fmodify fstL (\n -> bool Nothing (Just (n * 2)) (even n)) (10, "abc")
186186+-- Just (20,"abc")
187187+--
188188+-- >>> fmodify fstL (\n -> bool Nothing (Just (n * 2)) (even n)) (11, "abc")
189189+-- Nothing
190190+fmodify ::
191191+ Functor f =>
192192+ Lens a b
193193+ -> (b -> f b)
194194+ -> a
195195+ -> f a
196196+fmodify =
197197+ error "todo: fmodify"
198198+199199+-- |
200200+--
201201+-- >>> fstL |= Just 3 $ (7, "abc")
202202+-- Just (3,"abc")
203203+--
204204+-- >>> (fstL |= (+1) $ (3, "abc")) 17
205205+-- (18,"abc")
206206+(|=) ::
207207+ Functor f =>
208208+ Lens a b
209209+ -> f b
210210+ -> a
211211+ -> f a
212212+(|=) =
213213+ error "todo: (|=)"
214214+215215+infixl 5 |=
216216+217217+-- |
218218+--
219219+-- >>> modify fstL (*10) (3, "abc")
220220+-- (30,"abc")
221221+--
222222+-- prop> let types = (x :: Int, y :: String) in getsetLaw fstL (x, y)
223223+--
224224+-- prop> let types = (x :: Int, y :: String) in setgetLaw fstL (x, y) z
225225+--
226226+-- prop> let types = (x :: Int, y :: String) in setsetLaw fstL (x, y) z
227227+fstL ::
228228+ Lens (x, y) x
229229+fstL =
230230+ error "todo: fstL"
231231+232232+-- |
233233+--
234234+-- >>> modify sndL (++ "def") (13, "abc")
235235+-- (13,"abcdef")
236236+--
237237+-- prop> let types = (x :: Int, y :: String) in getsetLaw sndL (x, y)
238238+--
239239+-- prop> let types = (x :: Int, y :: String) in setgetLaw sndL (x, y) z
240240+--
241241+-- prop> let types = (x :: Int, y :: String) in setsetLaw sndL (x, y) z
242242+sndL ::
243243+ Lens (x, y) y
244244+sndL =
245245+ error "todo: sndL"
246246+247247+-- |
248248+--
249249+-- >>> get (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d']))
250250+-- Just 'c'
251251+--
252252+-- >>> get (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d']))
253253+-- Nothing
254254+--
255255+-- >>> set (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) (Just 'X')
256256+-- fromList [(1,'a'),(2,'b'),(3,'X'),(4,'d')]
257257+--
258258+-- >>> set (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) (Just 'X')
259259+-- fromList [(1,'a'),(2,'b'),(3,'c'),(4,'d'),(33,'X')]
260260+--
261261+-- >>> set (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) Nothing
262262+-- fromList [(1,'a'),(2,'b'),(4,'d')]
263263+--
264264+-- >>> set (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) Nothing
265265+-- fromList [(1,'a'),(2,'b'),(3,'c'),(4,'d')]
266266+mapL ::
267267+ Ord k =>
268268+ k
269269+ -> Lens (Map k v) (Maybe v)
270270+mapL =
271271+ error "todo: mapL"
272272+273273+-- |
274274+--
275275+-- >>> get (setL 3) (Set.fromList [1..5])
276276+-- True
277277+--
278278+-- >>> get (setL 33) (Set.fromList [1..5])
279279+-- False
280280+--
281281+-- >>> set (setL 3) (Set.fromList [1..5]) True
282282+-- fromList [1,2,3,4,5]
283283+--
284284+-- >>> set (setL 3) (Set.fromList [1..5]) False
285285+-- fromList [1,2,4,5]
286286+--
287287+-- >>> set (setL 33) (Set.fromList [1..5]) True
288288+-- fromList [1,2,3,4,5,33]
289289+--
290290+-- >>> set (setL 33) (Set.fromList [1..5]) False
291291+-- fromList [1,2,3,4,5]
292292+setL ::
293293+ Ord k =>
294294+ k
295295+ -> Lens (Set k) Bool
296296+setL =
297297+ error "todo: setL"
298298+299299+-- |
300300+--
301301+-- >>> get (compose fstL sndL) ("abc", (7, "def"))
302302+-- 7
303303+--
304304+-- >>> set (compose fstL sndL) ("abc", (7, "def")) 8
305305+-- ("abc",(8,"def"))
306306+compose ::
307307+ Lens b c
308308+ -> Lens a b
309309+ -> Lens a c
310310+compose =
311311+ error "todo: compose"
312312+313313+-- | An alias for @compose@.
314314+(|.) ::
315315+ Lens b c
316316+ -> Lens a b
317317+ -> Lens a c
318318+(|.) =
319319+ compose
320320+321321+infixr 9 |.
322322+323323+-- |
324324+--
325325+-- >>> get identity 3
326326+-- 3
327327+--
328328+-- >>> set identity 3 4
329329+-- 4
330330+identity ::
331331+ Lens a a
332332+identity =
333333+ error "todo: identity"
334334+335335+-- |
336336+--
337337+-- >>> get (product fstL sndL) (("abc", 3), (4, "def"))
338338+-- ("abc","def")
339339+--
340340+-- >>> set (product fstL sndL) (("abc", 3), (4, "def")) ("ghi", "jkl")
341341+-- (("ghi",3),(4,"jkl"))
342342+product ::
343343+ Lens a b
344344+ -> Lens c d
345345+ -> Lens (a, c) (b, d)
346346+product =
347347+ error "todo: product"
348348+349349+-- | An alias for @product@.
350350+(***) ::
351351+ Lens a b
352352+ -> Lens c d
353353+ -> Lens (a, c) (b, d)
354354+(***) =
355355+ product
356356+357357+infixr 3 ***
358358+359359+-- |
360360+--
361361+-- >>> get (choice fstL sndL) (Left ("abc", 7))
362362+-- "abc"
363363+--
364364+-- >>> get (choice fstL sndL) (Right ("abc", 7))
365365+-- 7
366366+--
367367+-- >>> set (choice fstL sndL) (Left ("abc", 7)) "def"
368368+-- Left ("def",7)
369369+--
370370+-- >>> set (choice fstL sndL) (Right ("abc", 7)) 8
371371+-- Right ("abc",8)
372372+choice ::
373373+ Lens a x
374374+ -> Lens b x
375375+ -> Lens (Either a b) x
376376+choice =
377377+ error "todo: choice"
378378+379379+-- | An alias for @choice@.
380380+(|||) ::
381381+ Lens a x
382382+ -> Lens b x
383383+ -> Lens (Either a b) x
384384+(|||) =
385385+ choice
386386+387387+infixr 2 |||
388388+389389+----
390390+391391+cityL ::
392392+ Lens Locality String
393393+cityL =
394394+ Lens
395395+ (\(Locality _ t y) c -> Locality c t y)
396396+ (\(Locality c _ _) -> c)
397397+398398+stateL ::
399399+ Lens Locality String
400400+stateL =
401401+ Lens
402402+ (\(Locality c _ y) t -> Locality c t y)
403403+ (\(Locality _ t _) -> t)
404404+405405+countryL ::
406406+ Lens Locality String
407407+countryL =
408408+ Lens
409409+ (\(Locality c t _) y -> Locality c t y)
410410+ (\(Locality _ _ y) -> y)
411411+412412+streetL ::
413413+ Lens Address String
414414+streetL =
415415+ Lens
416416+ (\(Address _ s l) t -> Address t s l)
417417+ (\(Address t _ _) -> t)
418418+419419+suburbL ::
420420+ Lens Address String
421421+suburbL =
422422+ Lens
423423+ (\(Address t _ l) s -> Address t s l)
424424+ (\(Address _ s _) -> s)
425425+426426+localityL ::
427427+ Lens Address Locality
428428+localityL =
429429+ Lens
430430+ (\(Address t s _) l -> Address t s l)
431431+ (\(Address _ _ l) -> l)
432432+433433+ageL ::
434434+ Lens Person Int
435435+ageL =
436436+ Lens
437437+ (\(Person _ n d) a -> Person a n d)
438438+ (\(Person a _ _) -> a)
439439+440440+nameL ::
441441+ Lens Person String
442442+nameL =
443443+ Lens
444444+ (\(Person a _ d) n -> Person a n d)
445445+ (\(Person _ n _) -> n)
446446+447447+addressL ::
448448+ Lens Person Address
449449+addressL =
450450+ Lens
451451+ (\(Person a n _) d -> Person a n d)
452452+ (\(Person _ _ d) -> d)
453453+454454+-- |
455455+--
456456+-- >>> get (suburbL |. addressL) fred
457457+-- "Fredville"
458458+--
459459+-- >>> get (suburbL |. addressL) mary
460460+-- "Maryland"
461461+getSuburb ::
462462+ Person
463463+ -> String
464464+getSuburb =
465465+ error "todo: getSuburb"
466466+467467+-- |
468468+--
469469+-- >>> setStreet fred "Some Other St"
470470+-- Person 24 "Fred" (Address "Some Other St" "Fredville" (Locality "Fredmania" "New South Fred" "Fredalia"))
471471+--
472472+-- >>> setStreet mary "Some Other St"
473473+-- Person 28 "Mary" (Address "Some Other St" "Maryland" (Locality "Mary Mary" "Western Mary" "Maristan"))
474474+setStreet ::
475475+ Person
476476+ -> String
477477+ -> Person
478478+setStreet =
479479+ error "todo: setStreet"
480480+481481+-- |
482482+--
483483+-- >>> getAgeAndCountry (fred, maryLocality)
484484+-- (24,"Maristan")
485485+--
486486+-- >>> getAgeAndCountry (mary, fredLocality)
487487+-- (28,"Fredalia")
488488+getAgeAndCountry ::
489489+ (Person, Locality)
490490+ -> (Int, String)
491491+getAgeAndCountry =
492492+ error "todo: getAgeAndCountry"
493493+494494+-- |
495495+--
496496+-- >>> setCityAndLocality (fred, maryAddress) ("Some Other City", fredLocality)
497497+-- (Person 24 "Fred" (Address "15 Fred St" "Fredville" (Locality "Some Other City" "New South Fred" "Fredalia")),Address "83 Mary Ln" "Maryland" (Locality "Fredmania" "New South Fred" "Fredalia"))
498498+--
499499+-- >>> setCityAndLocality (mary, fredAddress) ("Some Other City", maryLocality)
500500+-- (Person 28 "Mary" (Address "83 Mary Ln" "Maryland" (Locality "Some Other City" "Western Mary" "Maristan")),Address "15 Fred St" "Fredville" (Locality "Mary Mary" "Western Mary" "Maristan"))
501501+setCityAndLocality ::
502502+ (Person, Address) -> (String, Locality) -> (Person, Address)
503503+setCityAndLocality =
504504+ error "todo: setCityAndLocality"
505505+506506+-- |
507507+--
508508+-- >>> getSuburbOrCity (Left maryAddress)
509509+-- "Maryland"
510510+--
511511+-- >>> getSuburbOrCity (Right fredLocality)
512512+-- "Fredmania"
513513+getSuburbOrCity ::
514514+ Either Address Locality
515515+ -> String
516516+getSuburbOrCity =
517517+ error "todo: getSuburbOrCity"
518518+519519+-- |
520520+--
521521+-- >>> setStreetOrState (Right maryLocality) "Some Other State"
522522+-- Right (Locality "Mary Mary" "Some Other State" "Maristan")
523523+--
524524+-- >>> setStreetOrState (Left fred) "Some Other St"
525525+-- Left (Person 24 "Fred" (Address "Some Other St" "Fredville" (Locality "Fredmania" "New South Fred" "Fredalia")))
526526+setStreetOrState ::
527527+ Either Person Locality
528528+ -> String
529529+ -> Either Person Locality
530530+setStreetOrState =
531531+ error "todo: setStreetOrState"
532532+533533+-- |
534534+--
535535+-- >>> modifyCityUppercase fred
536536+-- Person 24 "Fred" (Address "15 Fred St" "Fredville" (Locality "FREDMANIA" "New South Fred" "Fredalia"))
537537+--
538538+-- >>> modifyCityUppercase mary
539539+-- Person 28 "Mary" (Address "83 Mary Ln" "Maryland" (Locality "MARY MARY" "Western Mary" "Maristan"))
540540+modifyCityUppercase ::
541541+ Person
542542+ -> Person
543543+modifyCityUppercase =
544544+ error "todo: modifyCityUppercase"
+7
src/Lets/Lens.hs
···11+module Lets.Lens (
22+ module L
33+) where
44+55+import Lets.Lens.Choice as L
66+import Lets.Lens.Lens as L
77+import Lets.Lens.Profunctor as L
+43
src/Lets/Lens/Choice.hs
···11+module Lets.Lens.Choice
22+(
33+ Choice(..)
44+) where
55+66+import Lets.Data
77+import Lets.Lens.Profunctor
88+99+diswap ::
1010+ Profunctor p =>
1111+ p (Either a b) (Either c d)
1212+ -> p (Either b a) (Either d c)
1313+diswap =
1414+ let swap = either Right Left
1515+ in dimap swap swap
1616+1717+-- | Map on left or right of @Either@. Only one of @left@ or @right@ needs to be
1818+-- provided.
1919+class Profunctor p => Choice p where
2020+ left ::
2121+ p a b
2222+ -> p (Either a c) (Either b c)
2323+ left =
2424+ diswap . right
2525+2626+ right ::
2727+ p a b
2828+ -> p (Either c a) (Either c b)
2929+ right =
3030+ diswap . left
3131+3232+instance Choice (->) where
3333+ left f =
3434+ either (Left . f) Right
3535+ right f =
3636+ either Left (Right . f)
3737+3838+instance Choice Tagged where
3939+ left (Tagged x) =
4040+ Tagged (Left x)
4141+ right (Tagged x) =
4242+ Tagged (Right x)
4343+
+788
src/Lets/Lens/Lens.hs
···11+{-# LANGUAGE RankNTypes #-}
22+33+module Lets.Lens.Lens (
44+ fmapT
55+, over
66+, fmapTAgain
77+, Set
88+, sets
99+, mapped
1010+, set
1111+, foldMapT
1212+, foldMapOf
1313+, foldMapTAgain
1414+, Fold
1515+, folds
1616+, folded
1717+, Get
1818+, get
1919+, Traversal
2020+, both
2121+, traverseLeft
2222+, traverseRight
2323+, Traversal'
2424+, Lens
2525+, Prism
2626+, _Left
2727+, _Right
2828+, prism
2929+, _Just
3030+, _Nothing
3131+, setP
3232+, getP
3333+, Prism'
3434+, modify
3535+, (%~)
3636+, (.~)
3737+, fmodify
3838+, (|=)
3939+, fstL
4040+, sndL
4141+, mapL
4242+, setL
4343+, compose
4444+, (|.)
4545+, identity
4646+, product
4747+, (***)
4848+, choice
4949+, (|||)
5050+, Lens'
5151+, cityL
5252+, stateL
5353+, countryL
5454+, streetL
5555+, suburbL
5656+, localityL
5757+, ageL
5858+, nameL
5959+, addressL
6060+, intAndIntL
6161+, intAndL
6262+, getSuburb
6363+, setStreet
6464+, getAgeAndCountry
6565+, setCityAndLocality
6666+, getSuburbOrCity
6767+, setStreetOrState
6868+, modifyCityUppercase
6969+, modifyIntAndLengthEven
7070+, traverseLocality
7171+, intOrIntP
7272+, intOrP
7373+, intOrLengthEven
7474+) where
7575+7676+import Control.Applicative(Applicative(..))
7777+import Data.Bool(bool)
7878+import Data.Char(toUpper)
7979+import Data.Foldable(Foldable(..))
8080+import Data.Functor((<$>))
8181+import Data.Map(Map)
8282+import qualified Data.Map as Map(insert, delete, lookup)
8383+import Data.Monoid(Monoid(..))
8484+import qualified Data.Set as Set(Set, insert, delete, member)
8585+import Data.Traversable(Traversable(..))
8686+import Lets.Data
8787+import Lets.Lens.Choice
8888+import Lets.Lens.Profunctor
8989+import Prelude hiding (product)
9090+9191+-- $setup
9292+-- >>> import qualified Data.Map as Map(fromList)
9393+-- >>> import qualified Data.Set as Set(fromList)
9494+-- >>> import Data.Char(ord)
9595+9696+-- Let's remind ourselves of Traversable, noting Foldable and Functor.
9797+--
9898+-- class (Foldable t, Functor t) => Traversable t where
9999+-- traverse ::
100100+-- Applicative f =>
101101+-- (a -> f b)
102102+-- -> t a
103103+-- -> f (t b)
104104+105105+-- | Observe that @fmap@ can be recovered from @traverse@ using @Identity@.
106106+--
107107+-- /Reminder:/ fmap :: Functor t => (a -> b) -> t a -> t b
108108+fmapT ::
109109+ Traversable t =>
110110+ (a -> b)
111111+ -> t a
112112+ -> t b
113113+fmapT =
114114+ error "todo: fmapT"
115115+116116+-- | Let's refactor out the call to @traverse@ as an argument to @fmapT@.
117117+over ::
118118+ ((a -> Identity b) -> s -> Identity t)
119119+ -> (a -> b)
120120+ -> s
121121+ -> t
122122+over =
123123+ error "todo: over"
124124+125125+-- | Here is @fmapT@ again, passing @traverse@ to @over@.
126126+fmapTAgain ::
127127+ Traversable t =>
128128+ (a -> b)
129129+ -> t a
130130+ -> t b
131131+fmapTAgain =
132132+ error "todo: fmapTAgain"
133133+134134+-- | Let's create a type-alias for this type of function.
135135+type Set s t a b =
136136+ (a -> Identity b)
137137+ -> s
138138+ -> Identity t
139139+140140+-- | Let's write an inverse to @over@ that does the @Identity@ wrapping &
141141+-- unwrapping.
142142+sets ::
143143+ ((a -> b) -> s -> t)
144144+ -> Set s t a b
145145+sets =
146146+ error "todo: sets"
147147+148148+mapped ::
149149+ Functor f =>
150150+ Set (f a) (f b) a b
151151+mapped =
152152+ error "todo: mapped"
153153+154154+set ::
155155+ Set s t a b
156156+ -> s
157157+ -> b
158158+ -> t
159159+set =
160160+ error "todo: set"
161161+162162+----
163163+164164+-- | Observe that @fmap@ can be recovered from @traverse@ using @Identity@.
165165+--
166166+-- /Reminder:/ foldMap :: (Foldable t, Monoid b) => (a -> b) -> t a -> b
167167+foldMapT ::
168168+ (Traversable t, Monoid b) =>
169169+ (a -> b)
170170+ -> t a
171171+ -> b
172172+foldMapT =
173173+ error "todo: foldMapT"
174174+175175+-- | Let's refactor out the call to @traverse@ as an argument to @foldMapT@.
176176+foldMapOf ::
177177+ ((a -> Const r b) -> s -> Const r t)
178178+ -> (a -> r)
179179+ -> s
180180+ -> r
181181+foldMapOf =
182182+ error "todo: foldMapOf"
183183+184184+-- | Here is @foldMapT@ again, passing @traverse@ to @foldMapOf@.
185185+foldMapTAgain ::
186186+ (Traversable t, Monoid b) =>
187187+ (a -> b)
188188+ -> t a
189189+ -> b
190190+foldMapTAgain =
191191+ error "todo: foldMapTAgain"
192192+193193+-- | Let's create a type-alias for this type of function.
194194+type Fold s t a b =
195195+ forall r.
196196+ Monoid r =>
197197+ (a -> Const r b)
198198+ -> s
199199+ -> Const r t
200200+201201+-- | Let's write an inverse to @foldMapOf@ that does the @Const@ wrapping &
202202+-- unwrapping.
203203+folds ::
204204+ ((a -> b) -> s -> t)
205205+ -> (a -> Const b a)
206206+ -> s
207207+ -> Const t s
208208+folds =
209209+ error "todo: folds"
210210+211211+folded ::
212212+ Foldable f =>
213213+ Fold (f a) (f a) a a
214214+folded =
215215+ error "todo: folded"
216216+217217+----
218218+219219+-- | @Get@ is like @Fold@, but without the @Monoid@ constraint.
220220+type Get r s a =
221221+ (a -> Const r a)
222222+ -> s
223223+ -> Const r s
224224+225225+get ::
226226+ Get a s a
227227+ -> s
228228+ -> a
229229+get =
230230+ error "todo: get"
231231+232232+----
233233+234234+-- | Let's generalise @Identity@ and @Const r@ to any @Applicative@ instance.
235235+type Traversal s t a b =
236236+ forall f.
237237+ Applicative f =>
238238+ (a -> f b)
239239+ -> s
240240+ -> f t
241241+242242+-- | Traverse both sides of a pair.
243243+both ::
244244+ Traversal (a, a) (b, b) a b
245245+both =
246246+ error "todo: both"
247247+248248+-- | Traverse the left side of @Either@.
249249+traverseLeft ::
250250+ Traversal (Either a x) (Either b x) a b
251251+traverseLeft =
252252+ error "todo: traverseLeft"
253253+254254+-- | Traverse the right side of @Either@.
255255+traverseRight ::
256256+ Traversal (Either x a) (Either x b) a b
257257+traverseRight =
258258+ error "todo: traverseRight"
259259+260260+type Traversal' a b =
261261+ Traversal a a b b
262262+263263+----
264264+265265+-- | @Const r@ is @Applicative@, if @Monoid r@, however, without the @Monoid@
266266+-- constraint (as in @Get@), the only shared abstraction between @Identity@ and
267267+-- @Const r@ is @Functor@.
268268+--
269269+-- Consequently, we arrive at our lens derivation:
270270+type Lens s t a b =
271271+ forall f.
272272+ Functor f =>
273273+ (a -> f b)
274274+ -> s
275275+ -> f t
276276+277277+----
278278+279279+-- | A prism is a less specific type of traversal.
280280+type Prism s t a b =
281281+ forall p f.
282282+ (Choice p, Applicative f) =>
283283+ p a (f b)
284284+ -> p s (f t)
285285+286286+_Left ::
287287+ Prism (Either a x) (Either b x) a b
288288+_Left =
289289+ error "todo: _Left"
290290+291291+_Right ::
292292+ Prism (Either x a) (Either x b) a b
293293+_Right =
294294+ error "todo: _Right"
295295+296296+prism ::
297297+ (b -> t)
298298+ -> (s -> Either t a)
299299+ -> Prism s t a b
300300+prism =
301301+ error "todo: prism"
302302+303303+_Just ::
304304+ Prism (Maybe a) (Maybe b) a b
305305+_Just =
306306+ error "todo: _Just"
307307+308308+_Nothing ::
309309+ Prism (Maybe a) (Maybe a) () ()
310310+_Nothing =
311311+ error "todo: _Nothing"
312312+313313+setP ::
314314+ Prism s t a b
315315+ -> s
316316+ -> Either t a
317317+setP =
318318+ error "todo: setP"
319319+320320+getP ::
321321+ Prism s t a b
322322+ -> b
323323+ -> t
324324+getP =
325325+ error "todo: getP"
326326+327327+type Prism' a b =
328328+ Prism a a b b
329329+330330+----
331331+332332+-- |
333333+--
334334+-- >>> modify fstL (+1) (0 :: Int, "abc")
335335+-- (1,"abc")
336336+--
337337+-- >>> modify sndL (+1) ("abc", 0 :: Int)
338338+-- ("abc",1)
339339+--
340340+-- prop> let types = (x :: Int, y :: String) in modify fstL id (x, y) == (x, y)
341341+--
342342+-- prop> let types = (x :: Int, y :: String) in modify sndL id (x, y) == (x, y)
343343+modify ::
344344+ Lens s t a b
345345+ -> (a -> b)
346346+ -> s
347347+ -> t
348348+modify =
349349+ error "todo: modify"
350350+351351+-- | An alias for @modify@.
352352+(%~) ::
353353+ Lens s t a b
354354+ -> (a -> b)
355355+ -> s
356356+ -> t
357357+(%~) =
358358+ modify
359359+360360+infixr 4 %~
361361+362362+-- |
363363+--
364364+-- >>> fstL .~ 1 $ (0 :: Int, "abc")
365365+-- (1,"abc")
366366+--
367367+-- >>> sndL .~ 1 $ ("abc", 0 :: Int)
368368+-- ("abc",1)
369369+--
370370+-- prop> let types = (x :: Int, y :: String) in set fstL (x, y) z == (fstL .~ z $ (x, y))
371371+--
372372+-- prop> let types = (x :: Int, y :: String) in set sndL (x, y) z == (sndL .~ z $ (x, y))
373373+(.~) ::
374374+ Lens s t a b
375375+ -> b
376376+ -> s
377377+ -> t
378378+(.~) =
379379+ error "todo: (.~)"
380380+381381+infixl 5 .~
382382+383383+-- |
384384+--
385385+-- >>> fmodify fstL (+) (5 :: Int, "abc") 8
386386+-- (13,"abc")
387387+--
388388+-- >>> fmodify fstL (\n -> bool Nothing (Just (n * 2)) (even n)) (10, "abc")
389389+-- Just (20,"abc")
390390+--
391391+-- >>> fmodify fstL (\n -> bool Nothing (Just (n * 2)) (even n)) (11, "abc")
392392+-- Nothing
393393+fmodify ::
394394+ Functor f =>
395395+ Lens s t a b
396396+ -> (a -> f b)
397397+ -> s
398398+ -> f t
399399+fmodify =
400400+ error "todo: fmodify"
401401+402402+-- |
403403+--
404404+-- >>> fstL |= Just 3 $ (7, "abc")
405405+-- Just (3,"abc")
406406+--
407407+-- >>> (fstL |= (+1) $ (3, "abc")) 17
408408+-- (18,"abc")
409409+(|=) ::
410410+ Functor f =>
411411+ Lens s t a b
412412+ -> f b
413413+ -> s
414414+ -> f t
415415+(|=) =
416416+ error "todo: (|=)"
417417+418418+infixl 5 |=
419419+420420+-- |
421421+--
422422+-- >>> modify fstL (*10) (3, "abc")
423423+-- (30,"abc")
424424+fstL ::
425425+ Lens (a, x) (b, x) a b
426426+fstL =
427427+ error "todo: fstL"
428428+429429+-- |
430430+--
431431+-- >>> modify sndL (++ "def") (13, "abc")
432432+-- (13,"abcdef")
433433+sndL ::
434434+ Lens (x, a) (x, b) a b
435435+sndL =
436436+ error "todo: sndL"
437437+438438+-- |
439439+--
440440+-- >>> get (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d']))
441441+-- Just 'c'
442442+--
443443+-- >>> get (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d']))
444444+-- Nothing
445445+--
446446+-- >>> set (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) (Just 'X')
447447+-- fromList [(1,'a'),(2,'b'),(3,'X'),(4,'d')]
448448+--
449449+-- >>> set (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) (Just 'X')
450450+-- fromList [(1,'a'),(2,'b'),(3,'c'),(4,'d'),(33,'X')]
451451+--
452452+-- >>> set (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) Nothing
453453+-- fromList [(1,'a'),(2,'b'),(4,'d')]
454454+--
455455+-- >>> set (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) Nothing
456456+-- fromList [(1,'a'),(2,'b'),(3,'c'),(4,'d')]
457457+mapL ::
458458+ Ord k =>
459459+ k
460460+ -> Lens (Map k v) (Map k v) (Maybe v) (Maybe v)
461461+mapL =
462462+ error "todo: mapL"
463463+464464+-- |
465465+--
466466+-- >>> get (setL 3) (Set.fromList [1..5])
467467+-- True
468468+--
469469+-- >>> get (setL 33) (Set.fromList [1..5])
470470+-- False
471471+--
472472+-- >>> set (setL 3) (Set.fromList [1..5]) True
473473+-- fromList [1,2,3,4,5]
474474+--
475475+-- >>> set (setL 3) (Set.fromList [1..5]) False
476476+-- fromList [1,2,4,5]
477477+--
478478+-- >>> set (setL 33) (Set.fromList [1..5]) True
479479+-- fromList [1,2,3,4,5,33]
480480+--
481481+-- >>> set (setL 33) (Set.fromList [1..5]) False
482482+-- fromList [1,2,3,4,5]
483483+setL ::
484484+ Ord k =>
485485+ k
486486+ -> Lens (Set.Set k) (Set.Set k) Bool Bool
487487+setL =
488488+ error "todo: setL"
489489+490490+-- |
491491+--
492492+-- >>> get (compose fstL sndL) ("abc", (7, "def"))
493493+-- 7
494494+--
495495+-- >>> set (compose fstL sndL) ("abc", (7, "def")) 8
496496+-- ("abc",(8,"def"))
497497+compose ::
498498+ Lens s t a b
499499+ -> Lens q r s t
500500+ -> Lens q r a b
501501+compose =
502502+ error "todo: compose"
503503+504504+-- | An alias for @compose@.
505505+(|.) ::
506506+ Lens s t a b
507507+ -> Lens q r s t
508508+ -> Lens q r a b
509509+(|.) =
510510+ compose
511511+512512+infixr 9 |.
513513+514514+-- |
515515+--
516516+-- >>> get identity 3
517517+-- 3
518518+--
519519+-- >>> set identity 3 4
520520+-- 4
521521+identity ::
522522+ Lens a b a b
523523+identity =
524524+ error "todo: identity"
525525+526526+-- |
527527+--
528528+-- >>> get (product fstL sndL) (("abc", 3), (4, "def"))
529529+-- ("abc","def")
530530+--
531531+-- >>> set (product fstL sndL) (("abc", 3), (4, "def")) ("ghi", "jkl")
532532+-- (("ghi",3),(4,"jkl"))
533533+product ::
534534+ Lens s t a b
535535+ -> Lens q r c d
536536+ -> Lens (s, q) (t, r) (a, c) (b, d)
537537+product =
538538+ error "todo: product"
539539+540540+-- | An alias for @product@.
541541+(***) ::
542542+ Lens s t a b
543543+ -> Lens q r c d
544544+ -> Lens (s, q) (t, r) (a, c) (b, d)
545545+(***) =
546546+ product
547547+548548+infixr 3 ***
549549+550550+-- |
551551+--
552552+-- >>> get (choice fstL sndL) (Left ("abc", 7))
553553+-- "abc"
554554+--
555555+-- >>> get (choice fstL sndL) (Right ("abc", 7))
556556+-- 7
557557+--
558558+-- >>> set (choice fstL sndL) (Left ("abc", 7)) "def"
559559+-- Left ("def",7)
560560+--
561561+-- >>> set (choice fstL sndL) (Right ("abc", 7)) 8
562562+-- Right ("abc",8)
563563+choice ::
564564+ Lens s t a b
565565+ -> Lens q r a b
566566+ -> Lens (Either s q) (Either t r) a b
567567+choice =
568568+ error "todo: choice"
569569+570570+-- | An alias for @choice@.
571571+(|||) ::
572572+ Lens s t a b
573573+ -> Lens q r a b
574574+ -> Lens (Either s q) (Either t r) a b
575575+(|||) =
576576+ choice
577577+578578+infixr 2 |||
579579+580580+----
581581+582582+type Lens' a b =
583583+ Lens a a b b
584584+585585+cityL ::
586586+ Lens' Locality String
587587+cityL p (Locality c t y) =
588588+ fmap (\c' -> Locality c' t y) (p c)
589589+590590+stateL ::
591591+ Lens' Locality String
592592+stateL p (Locality c t y) =
593593+ fmap (\t' -> Locality c t' y) (p t)
594594+595595+countryL ::
596596+ Lens' Locality String
597597+countryL p (Locality c t y) =
598598+ fmap (\y' -> Locality c t y') (p y)
599599+600600+streetL ::
601601+ Lens' Address String
602602+streetL p (Address t s l) =
603603+ fmap (\t' -> Address t' s l) (p t)
604604+605605+suburbL ::
606606+ Lens' Address String
607607+suburbL p (Address t s l) =
608608+ fmap (\s' -> Address t s' l) (p s)
609609+610610+localityL ::
611611+ Lens' Address Locality
612612+localityL p (Address t s l) =
613613+ fmap (\l' -> Address t s l') (p l)
614614+615615+ageL ::
616616+ Lens' Person Int
617617+ageL p (Person a n d) =
618618+ fmap (\a' -> Person a' n d) (p a)
619619+620620+nameL ::
621621+ Lens' Person String
622622+nameL p (Person a n d) =
623623+ fmap (\n' -> Person a n' d) (p n)
624624+625625+addressL ::
626626+ Lens' Person Address
627627+addressL p (Person a n d) =
628628+ fmap (\d' -> Person a n d') (p d)
629629+630630+intAndIntL ::
631631+ Lens' (IntAnd a) Int
632632+intAndIntL p (IntAnd n a) =
633633+ fmap (\n' -> IntAnd n' a) (p n)
634634+635635+-- lens for polymorphic update
636636+intAndL ::
637637+ Lens (IntAnd a) (IntAnd b) a b
638638+intAndL p (IntAnd n a) =
639639+ fmap (\a' -> IntAnd n a') (p a)
640640+641641+-- |
642642+--
643643+-- >>> get (suburbL |. addressL) fred
644644+-- "Fredville"
645645+--
646646+-- >>> get (suburbL |. addressL) mary
647647+-- "Maryland"
648648+getSuburb ::
649649+ Person
650650+ -> String
651651+getSuburb =
652652+ error "todo: getSuburb"
653653+654654+-- |
655655+--
656656+-- >>> setStreet fred "Some Other St"
657657+-- Person 24 "Fred" (Address "Some Other St" "Fredville" (Locality "Fredmania" "New South Fred" "Fredalia"))
658658+--
659659+-- >>> setStreet mary "Some Other St"
660660+-- Person 28 "Mary" (Address "Some Other St" "Maryland" (Locality "Mary Mary" "Western Mary" "Maristan"))
661661+setStreet ::
662662+ Person
663663+ -> String
664664+ -> Person
665665+setStreet =
666666+ error "todo: setStreet"
667667+668668+-- |
669669+--
670670+-- >>> getAgeAndCountry (fred, maryLocality)
671671+-- (24,"Maristan")
672672+--
673673+-- >>> getAgeAndCountry (mary, fredLocality)
674674+-- (28,"Fredalia")
675675+getAgeAndCountry ::
676676+ (Person, Locality)
677677+ -> (Int, String)
678678+getAgeAndCountry =
679679+ error "todo: getAgeAndCountry"
680680+681681+-- |
682682+--
683683+-- >>> setCityAndLocality (fred, maryAddress) ("Some Other City", fredLocality)
684684+-- (Person 24 "Fred" (Address "15 Fred St" "Fredville" (Locality "Some Other City" "New South Fred" "Fredalia")),Address "83 Mary Ln" "Maryland" (Locality "Fredmania" "New South Fred" "Fredalia"))
685685+--
686686+-- >>> setCityAndLocality (mary, fredAddress) ("Some Other City", maryLocality)
687687+-- (Person 28 "Mary" (Address "83 Mary Ln" "Maryland" (Locality "Some Other City" "Western Mary" "Maristan")),Address "15 Fred St" "Fredville" (Locality "Mary Mary" "Western Mary" "Maristan"))
688688+setCityAndLocality ::
689689+ (Person, Address) -> (String, Locality) -> (Person, Address)
690690+setCityAndLocality =
691691+ error "todo: setCityAndLocality"
692692+693693+-- |
694694+--
695695+-- >>> getSuburbOrCity (Left maryAddress)
696696+-- "Maryland"
697697+--
698698+-- >>> getSuburbOrCity (Right fredLocality)
699699+-- "Fredmania"
700700+getSuburbOrCity ::
701701+ Either Address Locality
702702+ -> String
703703+getSuburbOrCity =
704704+ error "todo: getSuburbOrCity"
705705+706706+-- |
707707+--
708708+-- >>> setStreetOrState (Right maryLocality) "Some Other State"
709709+-- Right (Locality "Mary Mary" "Some Other State" "Maristan")
710710+--
711711+-- >>> setStreetOrState (Left fred) "Some Other St"
712712+-- Left (Person 24 "Fred" (Address "Some Other St" "Fredville" (Locality "Fredmania" "New South Fred" "Fredalia")))
713713+setStreetOrState ::
714714+ Either Person Locality
715715+ -> String
716716+ -> Either Person Locality
717717+setStreetOrState =
718718+ error "todo: setStreetOrState"
719719+720720+-- |
721721+--
722722+-- >>> modifyCityUppercase fred
723723+-- Person 24 "Fred" (Address "15 Fred St" "Fredville" (Locality "FREDMANIA" "New South Fred" "Fredalia"))
724724+--
725725+-- >>> modifyCityUppercase mary
726726+-- Person 28 "Mary" (Address "83 Mary Ln" "Maryland" (Locality "MARY MARY" "Western Mary" "Maristan"))
727727+modifyCityUppercase ::
728728+ Person
729729+ -> Person
730730+modifyCityUppercase =
731731+ error "todo: modifyCityUppercase"
732732+733733+-- |
734734+--
735735+-- >>> modifyIntAndLengthEven (IntAnd 10 "abc")
736736+-- IntAnd 10 False
737737+--
738738+-- >>> modifyIntAndLengthEven (IntAnd 10 "abcd")
739739+-- IntAnd 10 True
740740+modifyIntAndLengthEven ::
741741+ IntAnd [a]
742742+ -> IntAnd Bool
743743+modifyIntAndLengthEven =
744744+ error "todo: modifyIntAndLengthEven"
745745+746746+----
747747+748748+-- |
749749+--
750750+-- >>> over traverseLocality (map toUpper) (Locality "abc" "def" "ghi")
751751+-- Locality "ABC" "DEF" "GHI"
752752+traverseLocality ::
753753+ Traversal' Locality String
754754+traverseLocality =
755755+ error "todo: traverseLocality"
756756+757757+-- |
758758+--
759759+-- >>> over intOrIntP (*10) (IntOrIs 3)
760760+-- IntOrIs 30
761761+--
762762+-- >>> over intOrIntP (*10) (IntOrIsNot "abc")
763763+-- IntOrIsNot "abc"
764764+intOrIntP ::
765765+ Prism' (IntOr a) Int
766766+intOrIntP =
767767+ error "todo: intOrIntP"
768768+769769+intOrP ::
770770+ Prism (IntOr a) (IntOr b) a b
771771+intOrP =
772772+ error "todo: intOrP"
773773+774774+-- |
775775+--
776776+-- >> over intOrP (even . length) (IntOrIsNot "abc")
777777+-- IntOrIsNot False
778778+--
779779+-- >>> over intOrP (even . length) (IntOrIsNot "abcd")
780780+-- IntOrIsNot True
781781+--
782782+-- >>> over intOrP (even . length) (IntOrIs 10)
783783+-- IntOrIs 10
784784+intOrLengthEven ::
785785+ IntOr [a]
786786+ -> IntOr Bool
787787+intOrLengthEven =
788788+ error "todo: intOrLengthEven"
+22
src/Lets/Lens/Profunctor.hs
···11+module Lets.Lens.Profunctor
22+(
33+ Profunctor(dimap)
44+) where
55+66+import Lets.Data
77+88+-- | A profunctor is a binary functor, with the first argument in contravariant
99+-- (negative) position and the second argument in covariant (positive) position.
1010+class Profunctor p where
1111+ dimap ::
1212+ (b -> a)
1313+ -> (c -> d)
1414+ -> p a c
1515+ -> p b d
1616+1717+instance Profunctor (->) where
1818+ dimap f g = \h -> g . h . f
1919+2020+instance Profunctor Tagged where
2121+ dimap _ g (Tagged x) =
2222+ Tagged (g x)
+546
src/Lets/OpticPolyLens.hs
···11+{-# LANGUAGE RankNTypes #-}
22+33+module Lets.OpticPolyLens (
44+ Lens(..)
55+, getsetLaw
66+, setgetLaw
77+, setsetLaw
88+, get
99+, set
1010+, modify
1111+, (%~)
1212+, fmodify
1313+, (|=)
1414+, fstL
1515+, sndL
1616+, mapL
1717+, setL
1818+, compose
1919+, (|.)
2020+, identity
2121+, product
2222+, (***)
2323+, choice
2424+, (|||)
2525+, cityL
2626+, countryL
2727+, streetL
2828+, suburbL
2929+, localityL
3030+, ageL
3131+, nameL
3232+, addressL
3333+, intAndIntL
3434+, intAndL
3535+, getSuburb
3636+, setStreet
3737+, getAgeAndCountry
3838+, setCityAndLocality
3939+, getSuburbOrCity
4040+, setStreetOrState
4141+, modifyCityUppercase
4242+, modifyIntandLengthEven
4343+) where
4444+4545+import Data.Bool(bool)
4646+import Data.Char(toUpper)
4747+import Data.Map(Map)
4848+import qualified Data.Map as Map(insert, delete, lookup)
4949+import Data.Set(Set)
5050+import qualified Data.Set as Set(insert, delete, member)
5151+import Lets.Data
5252+import Prelude hiding (product)
5353+5454+-- $setup
5555+-- >>> import qualified Data.Map as Map(fromList)
5656+-- >>> import qualified Data.Set as Set(fromList)
5757+-- >>> import Data.Char(ord)
5858+5959+data Lens s t a b =
6060+ Lens
6161+ (forall f. Functor f => (a -> f b) -> s -> f t)
6262+6363+get ::
6464+ Lens s t a b
6565+ -> s
6666+ -> a
6767+get (Lens r) =
6868+ getConst . r Const
6969+7070+set ::
7171+ Lens s t a b
7272+ -> s
7373+ -> b
7474+ -> t
7575+set (Lens r) a b =
7676+ getIdentity (r (const (Identity b)) a)
7777+7878+-- | The get/set law of lenses. This function should always return @True@.
7979+getsetLaw ::
8080+ Eq s =>
8181+ Lens s s a a
8282+ -> s
8383+ -> Bool
8484+getsetLaw l =
8585+ \a -> set l a (get l a) == a
8686+8787+-- | The set/get law of lenses. This function should always return @True@.
8888+setgetLaw ::
8989+ Eq a =>
9090+ Lens s s a a
9191+ -> s
9292+ -> a
9393+ -> Bool
9494+setgetLaw l a b =
9595+ get l (set l a b) == b
9696+9797+-- | The set/set law of lenses. This function should always return @True@.
9898+setsetLaw ::
9999+ Eq s =>
100100+ Lens s s a b
101101+ -> s
102102+ -> b
103103+ -> b
104104+ -> Bool
105105+setsetLaw l a b1 b2 =
106106+ set l (set l a b1) b2 == set l a b2
107107+108108+----
109109+110110+-- |
111111+--
112112+-- >>> modify fstL (+1) (0 :: Int, "abc")
113113+-- (1,"abc")
114114+--
115115+-- >>> modify sndL (+1) ("abc", 0 :: Int)
116116+-- ("abc",1)
117117+--
118118+-- prop> let types = (x :: Int, y :: String) in modify fstL id (x, y) == (x, y)
119119+--
120120+-- prop> let types = (x :: Int, y :: String) in modify sndL id (x, y) == (x, y)
121121+modify ::
122122+ Lens s t a b
123123+ -> (a -> b)
124124+ -> s
125125+ -> t
126126+modify =
127127+ error "todo: modify"
128128+129129+-- | An alias for @modify@.
130130+(%~) ::
131131+ Lens s t a b
132132+ -> (a -> b)
133133+ -> s
134134+ -> t
135135+(%~) =
136136+ modify
137137+138138+infixr 4 %~
139139+140140+-- |
141141+--
142142+-- >>> fstL .~ 1 $ (0 :: Int, "abc")
143143+-- (1,"abc")
144144+--
145145+-- >>> sndL .~ 1 $ ("abc", 0 :: Int)
146146+-- ("abc",1)
147147+--
148148+-- prop> let types = (x :: Int, y :: String) in set fstL (x, y) z == (fstL .~ z $ (x, y))
149149+--
150150+-- prop> let types = (x :: Int, y :: String) in set sndL (x, y) z == (sndL .~ z $ (x, y))
151151+(.~) ::
152152+ Lens s t a b
153153+ -> b
154154+ -> s
155155+ -> t
156156+(.~) =
157157+ error "todo: (.~)"
158158+159159+infixl 5 .~
160160+161161+-- |
162162+--
163163+-- >>> fmodify fstL (+) (5 :: Int, "abc") 8
164164+-- (13,"abc")
165165+--
166166+-- >>> fmodify fstL (\n -> bool Nothing (Just (n * 2)) (even n)) (10, "abc")
167167+-- Just (20,"abc")
168168+--
169169+-- >>> fmodify fstL (\n -> bool Nothing (Just (n * 2)) (even n)) (11, "abc")
170170+-- Nothing
171171+fmodify ::
172172+ Functor f =>
173173+ Lens s t a b
174174+ -> (a -> f b)
175175+ -> s
176176+ -> f t
177177+fmodify =
178178+ error "todo: fmodify"
179179+180180+-- |
181181+--
182182+-- >>> fstL |= Just 3 $ (7, "abc")
183183+-- Just (3,"abc")
184184+--
185185+-- >>> (fstL |= (+1) $ (3, "abc")) 17
186186+-- (18,"abc")
187187+(|=) ::
188188+ Functor f =>
189189+ Lens s t a b
190190+ -> f b
191191+ -> s
192192+ -> f t
193193+(|=) =
194194+ error "todo: (|=)"
195195+196196+infixl 5 |=
197197+198198+-- |
199199+--
200200+-- >>> modify fstL (*10) (3, "abc")
201201+-- (30,"abc")
202202+--
203203+-- prop> let types = (x :: Int, y :: String) in getsetLaw fstL (x, y)
204204+--
205205+-- prop> let types = (x :: Int, y :: String) in setgetLaw fstL (x, y) z
206206+--
207207+-- prop> let types = (x :: Int, y :: String) in setsetLaw fstL (x, y) z
208208+fstL ::
209209+ Lens (a, x) (b, x) a b
210210+fstL =
211211+ error "todo: fstL"
212212+213213+-- |
214214+--
215215+-- >>> modify sndL (++ "def") (13, "abc")
216216+-- (13,"abcdef")
217217+--
218218+-- prop> let types = (x :: Int, y :: String) in getsetLaw sndL (x, y)
219219+--
220220+-- prop> let types = (x :: Int, y :: String) in setgetLaw sndL (x, y) z
221221+--
222222+-- prop> let types = (x :: Int, y :: String) in setsetLaw sndL (x, y) z
223223+sndL ::
224224+ Lens (x, a) (x, b) a b
225225+sndL =
226226+ error "todo: sndL"
227227+228228+-- |
229229+--
230230+-- >>> get (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d']))
231231+-- Just 'c'
232232+--
233233+-- >>> get (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d']))
234234+-- Nothing
235235+--
236236+-- >>> set (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) (Just 'X')
237237+-- fromList [(1,'a'),(2,'b'),(3,'X'),(4,'d')]
238238+--
239239+-- >>> set (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) (Just 'X')
240240+-- fromList [(1,'a'),(2,'b'),(3,'c'),(4,'d'),(33,'X')]
241241+--
242242+-- >>> set (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) Nothing
243243+-- fromList [(1,'a'),(2,'b'),(4,'d')]
244244+--
245245+-- >>> set (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) Nothing
246246+-- fromList [(1,'a'),(2,'b'),(3,'c'),(4,'d')]
247247+mapL ::
248248+ Ord k =>
249249+ k
250250+ -> Lens (Map k v) (Map k v) (Maybe v) (Maybe v)
251251+mapL =
252252+ error "todo: mapL"
253253+254254+-- |
255255+--
256256+-- >>> get (setL 3) (Set.fromList [1..5])
257257+-- True
258258+--
259259+-- >>> get (setL 33) (Set.fromList [1..5])
260260+-- False
261261+--
262262+-- >>> set (setL 3) (Set.fromList [1..5]) True
263263+-- fromList [1,2,3,4,5]
264264+--
265265+-- >>> set (setL 3) (Set.fromList [1..5]) False
266266+-- fromList [1,2,4,5]
267267+--
268268+-- >>> set (setL 33) (Set.fromList [1..5]) True
269269+-- fromList [1,2,3,4,5,33]
270270+--
271271+-- >>> set (setL 33) (Set.fromList [1..5]) False
272272+-- fromList [1,2,3,4,5]
273273+setL ::
274274+ Ord k =>
275275+ k
276276+ -> Lens (Set k) (Set k) Bool Bool
277277+setL =
278278+ error "todo: setL"
279279+280280+-- |
281281+--
282282+-- >>> get (compose fstL sndL) ("abc", (7, "def"))
283283+-- 7
284284+--
285285+-- >>> set (compose fstL sndL) ("abc", (7, "def")) 8
286286+-- ("abc",(8,"def"))
287287+compose ::
288288+ Lens s t a b
289289+ -> Lens q r s t
290290+ -> Lens q r a b
291291+compose =
292292+ error "todo: compose"
293293+294294+-- | An alias for @compose@.
295295+(|.) ::
296296+ Lens s t a b
297297+ -> Lens q r s t
298298+ -> Lens q r a b
299299+(|.) =
300300+ compose
301301+302302+infixr 9 |.
303303+304304+-- |
305305+--
306306+-- >>> get identity 3
307307+-- 3
308308+--
309309+-- >>> set identity 3 4
310310+-- 4
311311+identity ::
312312+ Lens a b a b
313313+identity =
314314+ error "todo: identity"
315315+316316+-- |
317317+--
318318+-- >>> get (product fstL sndL) (("abc", 3), (4, "def"))
319319+-- ("abc","def")
320320+--
321321+-- >>> set (product fstL sndL) (("abc", 3), (4, "def")) ("ghi", "jkl")
322322+-- (("ghi",3),(4,"jkl"))
323323+product ::
324324+ Lens s t a b
325325+ -> Lens q r c d
326326+ -> Lens (s, q) (t, r) (a, c) (b, d)
327327+product =
328328+ error "todo: product"
329329+330330+-- | An alias for @product@.
331331+(***) ::
332332+ Lens s t a b
333333+ -> Lens q r c d
334334+ -> Lens (s, q) (t, r) (a, c) (b, d)
335335+(***) =
336336+ product
337337+338338+infixr 3 ***
339339+340340+-- |
341341+--
342342+-- >>> get (choice fstL sndL) (Left ("abc", 7))
343343+-- "abc"
344344+--
345345+-- >>> get (choice fstL sndL) (Right ("abc", 7))
346346+-- 7
347347+--
348348+-- >>> set (choice fstL sndL) (Left ("abc", 7)) "def"
349349+-- Left ("def",7)
350350+--
351351+-- >>> set (choice fstL sndL) (Right ("abc", 7)) 8
352352+-- Right ("abc",8)
353353+choice ::
354354+ Lens s t a b
355355+ -> Lens q r a b
356356+ -> Lens (Either s q) (Either t r) a b
357357+choice =
358358+ error "todo: choice"
359359+360360+-- | An alias for @choice@.
361361+(|||) ::
362362+ Lens s t a b
363363+ -> Lens q r a b
364364+ -> Lens (Either s q) (Either t r) a b
365365+(|||) =
366366+ choice
367367+368368+infixr 2 |||
369369+370370+----
371371+372372+type Lens' a b =
373373+ Lens a a b b
374374+375375+cityL ::
376376+ Lens' Locality String
377377+cityL =
378378+ Lens
379379+ (\p (Locality c t y) -> fmap (\c' -> Locality c' t y) (p c))
380380+381381+stateL ::
382382+ Lens' Locality String
383383+stateL =
384384+ Lens
385385+ (\p (Locality c t y) -> fmap (\t' -> Locality c t' y) (p t))
386386+387387+countryL ::
388388+ Lens' Locality String
389389+countryL =
390390+ Lens
391391+ (\p (Locality c t y) -> fmap (\y' -> Locality c t y') (p y))
392392+393393+streetL ::
394394+ Lens' Address String
395395+streetL =
396396+ Lens
397397+ (\p (Address t s l) -> fmap (\t' -> Address t' s l) (p t))
398398+399399+suburbL ::
400400+ Lens' Address String
401401+suburbL =
402402+ Lens
403403+ (\p (Address t s l) -> fmap (\s' -> Address t s' l) (p s))
404404+405405+localityL ::
406406+ Lens' Address Locality
407407+localityL =
408408+ Lens
409409+ (\p (Address t s l) -> fmap (\l' -> Address t s l') (p l))
410410+411411+ageL ::
412412+ Lens' Person Int
413413+ageL =
414414+ Lens
415415+ (\p (Person a n d) -> fmap (\a' -> Person a' n d) (p a))
416416+417417+nameL ::
418418+ Lens' Person String
419419+nameL =
420420+ Lens
421421+ (\p (Person a n d) -> fmap (\n' -> Person a n' d) (p n))
422422+423423+addressL ::
424424+ Lens' Person Address
425425+addressL =
426426+ Lens
427427+ (\p (Person a n d) -> fmap (\d' -> Person a n d') (p d))
428428+429429+intAndIntL ::
430430+ Lens' (IntAnd a) Int
431431+intAndIntL =
432432+ Lens
433433+ (\p (IntAnd n a) -> fmap (\n' -> IntAnd n' a) (p n))
434434+435435+-- lens for polymorphic update
436436+intAndL ::
437437+ Lens (IntAnd a) (IntAnd b) a b
438438+intAndL =
439439+ Lens
440440+ (\p (IntAnd n a) -> fmap (\a' -> IntAnd n a') (p a))
441441+442442+-- |
443443+--
444444+-- >>> get (suburbL |. addressL) fred
445445+-- "Fredville"
446446+--
447447+-- >>> get (suburbL |. addressL) mary
448448+-- "Maryland"
449449+getSuburb ::
450450+ Person
451451+ -> String
452452+getSuburb =
453453+ error "todo: getSuburb"
454454+455455+456456+-- |
457457+--
458458+-- >>> setStreet fred "Some Other St"
459459+-- Person 24 "Fred" (Address "Some Other St" "Fredville" (Locality "Fredmania" "New South Fred" "Fredalia"))
460460+--
461461+-- >>> setStreet mary "Some Other St"
462462+-- Person 28 "Mary" (Address "Some Other St" "Maryland" (Locality "Mary Mary" "Western Mary" "Maristan"))
463463+setStreet ::
464464+ Person
465465+ -> String
466466+ -> Person
467467+setStreet =
468468+ error "todo: setStreet"
469469+470470+-- |
471471+--
472472+-- >>> getAgeAndCountry (fred, maryLocality)
473473+-- (24,"Maristan")
474474+--
475475+-- >>> getAgeAndCountry (mary, fredLocality)
476476+-- (28,"Fredalia")
477477+getAgeAndCountry ::
478478+ (Person, Locality)
479479+ -> (Int, String)
480480+getAgeAndCountry =
481481+ error "todo: getAgeAndCountry"
482482+483483+-- |
484484+--
485485+-- >>> setCityAndLocality (fred, maryAddress) ("Some Other City", fredLocality)
486486+-- (Person 24 "Fred" (Address "15 Fred St" "Fredville" (Locality "Some Other City" "New South Fred" "Fredalia")),Address "83 Mary Ln" "Maryland" (Locality "Fredmania" "New South Fred" "Fredalia"))
487487+--
488488+-- >>> setCityAndLocality (mary, fredAddress) ("Some Other City", maryLocality)
489489+-- (Person 28 "Mary" (Address "83 Mary Ln" "Maryland" (Locality "Some Other City" "Western Mary" "Maristan")),Address "15 Fred St" "Fredville" (Locality "Mary Mary" "Western Mary" "Maristan"))
490490+setCityAndLocality ::
491491+ (Person, Address) -> (String, Locality) -> (Person, Address)
492492+setCityAndLocality =
493493+ error "todo: setCityAndLocality"
494494+495495+-- |
496496+--
497497+-- >>> getSuburbOrCity (Left maryAddress)
498498+-- "Maryland"
499499+--
500500+-- >>> getSuburbOrCity (Right fredLocality)
501501+-- "Fredmania"
502502+getSuburbOrCity ::
503503+ Either Address Locality
504504+ -> String
505505+getSuburbOrCity =
506506+ get (suburbL ||| cityL)
507507+508508+-- |
509509+--
510510+-- >>> setStreetOrState (Right maryLocality) "Some Other State"
511511+-- Right (Locality "Mary Mary" "Some Other State" "Maristan")
512512+--
513513+-- >>> setStreetOrState (Left fred) "Some Other St"
514514+-- Left (Person 24 "Fred" (Address "Some Other St" "Fredville" (Locality "Fredmania" "New South Fred" "Fredalia")))
515515+setStreetOrState ::
516516+ Either Person Locality
517517+ -> String
518518+ -> Either Person Locality
519519+setStreetOrState =
520520+ set (streetL |. addressL ||| stateL)
521521+522522+-- |
523523+--
524524+-- >>> modifyCityUppercase fred
525525+-- Person 24 "Fred" (Address "15 Fred St" "Fredville" (Locality "FREDMANIA" "New South Fred" "Fredalia"))
526526+--
527527+-- >>> modifyCityUppercase mary
528528+-- Person 28 "Mary" (Address "83 Mary Ln" "Maryland" (Locality "MARY MARY" "Western Mary" "Maristan"))
529529+modifyCityUppercase ::
530530+ Person
531531+ -> Person
532532+modifyCityUppercase =
533533+ cityL |. localityL |. addressL %~ map toUpper
534534+535535+-- |
536536+--
537537+-- >>> modify intAndL (even . length) (IntAnd 10 "abc")
538538+-- IntAnd 10 False
539539+--
540540+-- >>> modify intAndL (even . length) (IntAnd 10 "abcd")
541541+-- IntAnd 10 True
542542+modifyIntandLengthEven ::
543543+ IntAnd [a]
544544+ -> IntAnd Bool
545545+modifyIntandLengthEven =
546546+ intAndL %~ even . length
+592
src/Lets/StoreLens.hs
···11+module Lets.StoreLens (
22+ Store(..)
33+, setS
44+, getS
55+, mapS
66+, duplicateS
77+, extendS
88+, extractS
99+, Lens(..)
1010+, getsetLaw
1111+, setgetLaw
1212+, setsetLaw
1313+, get
1414+, set
1515+, modify
1616+, (%~)
1717+, fmodify
1818+, (|=)
1919+, fstL
2020+, sndL
2121+, mapL
2222+, setL
2323+, compose
2424+, (|.)
2525+, identity
2626+, product
2727+, (***)
2828+, choice
2929+, (|||)
3030+, cityL
3131+, countryL
3232+, streetL
3333+, suburbL
3434+, localityL
3535+, ageL
3636+, nameL
3737+, addressL
3838+, getSuburb
3939+, setStreet
4040+, getAgeAndCountry
4141+, setCityAndLocality
4242+, getSuburbOrCity
4343+, setStreetOrState
4444+, modifyCityUppercase
4545+) where
4646+4747+import Control.Applicative((<*>))
4848+import Data.Bool(bool)
4949+import Data.Char(toUpper)
5050+import Data.Functor((<$>))
5151+import Data.Map(Map)
5252+import qualified Data.Map as Map(insert, delete, lookup)
5353+import Data.Set(Set)
5454+import qualified Data.Set as Set(insert, delete, member)
5555+import Lets.Data
5656+import Prelude hiding (product)
5757+5858+-- $setup
5959+-- >>> import qualified Data.Map as Map(fromList)
6060+-- >>> import qualified Data.Set as Set(fromList)
6161+-- >>> import Data.Char(ord)
6262+6363+setS ::
6464+ Store s a
6565+ -> s
6666+ -> a
6767+setS (Store s _) =
6868+ s
6969+7070+getS ::
7171+ Store s a
7272+ -> s
7373+getS (Store _ g) =
7474+ g
7575+7676+mapS ::
7777+ (a -> b)
7878+ -> Store s a
7979+ -> Store s b
8080+mapS =
8181+ error "todo: mapS"
8282+8383+duplicateS ::
8484+ Store s a
8585+ -> Store s (Store s a)
8686+duplicateS =
8787+ error "todo: duplicateS"
8888+8989+extendS ::
9090+ (Store s a -> b)
9191+ -> Store s a
9292+ -> Store s b
9393+extendS =
9494+ error "todo: extendS"
9595+9696+extractS ::
9797+ Store s a
9898+ -> a
9999+extractS =
100100+ error "todo: extractS"
101101+102102+----
103103+104104+data Lens a b =
105105+ Lens
106106+ (a -> Store b a)
107107+108108+-- |
109109+--
110110+-- >>> get fstL (0 :: Int, "abc")
111111+-- 0
112112+--
113113+-- >>> get sndL ("abc", 0 :: Int)
114114+-- 0
115115+--
116116+-- prop> let types = (x :: Int, y :: String) in get fstL (x, y) == x
117117+--
118118+-- prop> let types = (x :: Int, y :: String) in get sndL (x, y) == y
119119+get ::
120120+ Lens a b
121121+ -> a
122122+ -> b
123123+get (Lens r) =
124124+ getS . r
125125+126126+-- |
127127+--
128128+-- >>> set fstL (0 :: Int, "abc") 1
129129+-- (1,"abc")
130130+--
131131+-- >>> set sndL ("abc", 0 :: Int) 1
132132+-- ("abc",1)
133133+--
134134+-- prop> let types = (x :: Int, y :: String) in set fstL (x, y) z == (z, y)
135135+--
136136+-- prop> let types = (x :: Int, y :: String) in set sndL (x, y) z == (x, z)
137137+set ::
138138+ Lens a b
139139+ -> a
140140+ -> b
141141+ -> a
142142+set (Lens r) =
143143+ setS . r
144144+145145+-- | The get/set law of lenses. This function should always return @True@.
146146+getsetLaw ::
147147+ Eq a =>
148148+ Lens a b
149149+ -> a
150150+ -> Bool
151151+getsetLaw l =
152152+ \a -> set l a (get l a) == a
153153+154154+-- | The set/get law of lenses. This function should always return @True@.
155155+setgetLaw ::
156156+ Eq b =>
157157+ Lens a b
158158+ -> a
159159+ -> b
160160+ -> Bool
161161+setgetLaw l a b =
162162+ get l (set l a b) == b
163163+164164+-- | The set/set law of lenses. This function should always return @True@.
165165+setsetLaw ::
166166+ Eq a =>
167167+ Lens a b
168168+ -> a
169169+ -> b
170170+ -> b
171171+ -> Bool
172172+setsetLaw l a b1 b2 =
173173+ set l (set l a b1) b2 == set l a b2
174174+175175+----
176176+177177+-- |
178178+--
179179+-- >>> modify fstL (+1) (0 :: Int, "abc")
180180+-- (1,"abc")
181181+--
182182+-- >>> modify sndL (+1) ("abc", 0 :: Int)
183183+-- ("abc",1)
184184+--
185185+-- prop> let types = (x :: Int, y :: String) in modify fstL id (x, y) == (x, y)
186186+--
187187+-- prop> let types = (x :: Int, y :: String) in modify sndL id (x, y) == (x, y)
188188+modify ::
189189+ Lens a b
190190+ -> (b -> b)
191191+ -> a
192192+ -> a
193193+modify =
194194+ error "todo: modify"
195195+196196+-- | An alias for @modify@.
197197+(%~) ::
198198+ Lens a b
199199+ -> (b -> b)
200200+ -> a
201201+ -> a
202202+(%~) =
203203+ modify
204204+205205+infixr 4 %~
206206+207207+-- |
208208+--
209209+-- >>> fstL .~ 1 $ (0 :: Int, "abc")
210210+-- (1,"abc")
211211+--
212212+-- >>> sndL .~ 1 $ ("abc", 0 :: Int)
213213+-- ("abc",1)
214214+--
215215+-- prop> let types = (x :: Int, y :: String) in set fstL (x, y) z == (fstL .~ z $ (x, y))
216216+--
217217+-- prop> let types = (x :: Int, y :: String) in set sndL (x, y) z == (sndL .~ z $ (x, y))
218218+(.~) ::
219219+ Lens a b
220220+ -> b
221221+ -> a
222222+ -> a
223223+(.~) =
224224+ error "todo: (.~)"
225225+226226+infixl 5 .~
227227+228228+-- |
229229+--
230230+-- >>> fmodify fstL (+) (5 :: Int, "abc") 8
231231+-- (13,"abc")
232232+--
233233+-- >>> fmodify fstL (\n -> bool Nothing (Just (n * 2)) (even n)) (10, "abc")
234234+-- Just (20,"abc")
235235+--
236236+-- >>> fmodify fstL (\n -> bool Nothing (Just (n * 2)) (even n)) (11, "abc")
237237+-- Nothing
238238+fmodify ::
239239+ Functor f =>
240240+ Lens a b
241241+ -> (b -> f b)
242242+ -> a
243243+ -> f a
244244+fmodify =
245245+ error "todo: fmodify"
246246+247247+-- |
248248+--
249249+-- >>> fstL |= Just 3 $ (7, "abc")
250250+-- Just (3,"abc")
251251+--
252252+-- >>> (fstL |= (+1) $ (3, "abc")) 17
253253+-- (18,"abc")
254254+(|=) ::
255255+ Functor f =>
256256+ Lens a b
257257+ -> f b
258258+ -> a
259259+ -> f a
260260+(|=) =
261261+ error "todo: (|=)"
262262+263263+infixl 5 |=
264264+265265+-- |
266266+--
267267+-- >>> modify fstL (*10) (3, "abc")
268268+-- (30,"abc")
269269+--
270270+-- prop> let types = (x :: Int, y :: String) in getsetLaw fstL (x, y)
271271+--
272272+-- prop> let types = (x :: Int, y :: String) in setgetLaw fstL (x, y) z
273273+--
274274+-- prop> let types = (x :: Int, y :: String) in setsetLaw fstL (x, y) z
275275+fstL ::
276276+ Lens (x, y) x
277277+fstL =
278278+ error "todo: fstL"
279279+280280+-- |
281281+--
282282+-- >>> modify sndL (++ "def") (13, "abc")
283283+-- (13,"abcdef")
284284+--
285285+-- prop> let types = (x :: Int, y :: String) in getsetLaw sndL (x, y)
286286+--
287287+-- prop> let types = (x :: Int, y :: String) in setgetLaw sndL (x, y) z
288288+--
289289+-- prop> let types = (x :: Int, y :: String) in setsetLaw sndL (x, y) z
290290+sndL ::
291291+ Lens (x, y) y
292292+sndL =
293293+ error "todo: sndL"
294294+295295+-- |
296296+--
297297+-- >>> get (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d']))
298298+-- Just 'c'
299299+--
300300+-- >>> get (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d']))
301301+-- Nothing
302302+--
303303+-- >>> set (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) (Just 'X')
304304+-- fromList [(1,'a'),(2,'b'),(3,'X'),(4,'d')]
305305+--
306306+-- >>> set (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) (Just 'X')
307307+-- fromList [(1,'a'),(2,'b'),(3,'c'),(4,'d'),(33,'X')]
308308+--
309309+-- >>> set (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) Nothing
310310+-- fromList [(1,'a'),(2,'b'),(4,'d')]
311311+--
312312+-- >>> set (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) Nothing
313313+-- fromList [(1,'a'),(2,'b'),(3,'c'),(4,'d')]
314314+mapL ::
315315+ Ord k =>
316316+ k
317317+ -> Lens (Map k v) (Maybe v)
318318+mapL =
319319+ error "todo: mapL"
320320+321321+-- |
322322+--
323323+-- >>> get (setL 3) (Set.fromList [1..5])
324324+-- True
325325+--
326326+-- >>> get (setL 33) (Set.fromList [1..5])
327327+-- False
328328+--
329329+-- >>> set (setL 3) (Set.fromList [1..5]) True
330330+-- fromList [1,2,3,4,5]
331331+--
332332+-- >>> set (setL 3) (Set.fromList [1..5]) False
333333+-- fromList [1,2,4,5]
334334+--
335335+-- >>> set (setL 33) (Set.fromList [1..5]) True
336336+-- fromList [1,2,3,4,5,33]
337337+--
338338+-- >>> set (setL 33) (Set.fromList [1..5]) False
339339+-- fromList [1,2,3,4,5]
340340+setL ::
341341+ Ord k =>
342342+ k
343343+ -> Lens (Set k) Bool
344344+setL =
345345+ error "todo: setL"
346346+347347+-- |
348348+--
349349+-- >>> get (compose fstL sndL) ("abc", (7, "def"))
350350+-- 7
351351+--
352352+-- >>> set (compose fstL sndL) ("abc", (7, "def")) 8
353353+-- ("abc",(8,"def"))
354354+compose ::
355355+ Lens b c
356356+ -> Lens a b
357357+ -> Lens a c
358358+compose =
359359+ error "todo: compose"
360360+361361+-- | An alias for @compose@.
362362+(|.) ::
363363+ Lens b c
364364+ -> Lens a b
365365+ -> Lens a c
366366+(|.) =
367367+ compose
368368+369369+infixr 9 |.
370370+371371+-- |
372372+--
373373+-- >>> get identity 3
374374+-- 3
375375+--
376376+-- >>> set identity 3 4
377377+-- 4
378378+identity ::
379379+ Lens a a
380380+identity =
381381+ error "todo: identity"
382382+383383+-- |
384384+--
385385+-- >>> get (product fstL sndL) (("abc", 3), (4, "def"))
386386+-- ("abc","def")
387387+--
388388+-- >>> set (product fstL sndL) (("abc", 3), (4, "def")) ("ghi", "jkl")
389389+-- (("ghi",3),(4,"jkl"))
390390+product ::
391391+ Lens a b
392392+ -> Lens c d
393393+ -> Lens (a, c) (b, d)
394394+product =
395395+ error "todo: product"
396396+397397+-- | An alias for @product@.
398398+(***) ::
399399+ Lens a b
400400+ -> Lens c d
401401+ -> Lens (a, c) (b, d)
402402+(***) =
403403+ product
404404+405405+infixr 3 ***
406406+407407+-- |
408408+--
409409+-- >>> get (choice fstL sndL) (Left ("abc", 7))
410410+-- "abc"
411411+--
412412+-- >>> get (choice fstL sndL) (Right ("abc", 7))
413413+-- 7
414414+--
415415+-- >>> set (choice fstL sndL) (Left ("abc", 7)) "def"
416416+-- Left ("def",7)
417417+--
418418+-- >>> set (choice fstL sndL) (Right ("abc", 7)) 8
419419+-- Right ("abc",8)
420420+choice ::
421421+ Lens a x
422422+ -> Lens b x
423423+ -> Lens (Either a b) x
424424+choice =
425425+ error "todo: choice"
426426+427427+-- | An alias for @choice@.
428428+(|||) ::
429429+ Lens a x
430430+ -> Lens b x
431431+ -> Lens (Either a b) x
432432+(|||) =
433433+ choice
434434+435435+infixr 2 |||
436436+437437+----
438438+439439+cityL ::
440440+ Lens Locality String
441441+cityL =
442442+ Lens
443443+ (\(Locality c t y) ->
444444+ Store (\c' -> Locality c' t y) c)
445445+446446+stateL ::
447447+ Lens Locality String
448448+stateL =
449449+ Lens
450450+ (\(Locality c t y) ->
451451+ Store (\t' -> Locality c t' y) t)
452452+453453+countryL ::
454454+ Lens Locality String
455455+countryL =
456456+ Lens
457457+ (\(Locality c t y) ->
458458+ Store (\y' -> Locality c t y') y)
459459+460460+streetL ::
461461+ Lens Address String
462462+streetL =
463463+ Lens
464464+ (\(Address t s l) ->
465465+ Store (\t' -> Address t' s l) t)
466466+467467+suburbL ::
468468+ Lens Address String
469469+suburbL =
470470+ Lens
471471+ (\(Address t s l) ->
472472+ Store (\s' -> Address t s' l) s)
473473+474474+localityL ::
475475+ Lens Address Locality
476476+localityL =
477477+ Lens
478478+ (\(Address t s l) ->
479479+ Store (\l' -> Address t s l') l)
480480+481481+ageL ::
482482+ Lens Person Int
483483+ageL =
484484+ Lens
485485+ (\(Person a n d) ->
486486+ Store (\a' -> Person a' n d) a)
487487+488488+nameL ::
489489+ Lens Person String
490490+nameL =
491491+ Lens
492492+ (\(Person a n d) ->
493493+ Store (\n' -> Person a n' d) n)
494494+495495+addressL ::
496496+ Lens Person Address
497497+addressL =
498498+ Lens
499499+ (\(Person a n d) ->
500500+ Store (\d' -> Person a n d') d)
501501+502502+-- |
503503+--
504504+-- >>> get (suburbL |. addressL) fred
505505+-- "Fredville"
506506+--
507507+-- >>> get (suburbL |. addressL) mary
508508+-- "Maryland"
509509+getSuburb ::
510510+ Person
511511+ -> String
512512+getSuburb =
513513+ error "todo: getSuburb"
514514+515515+-- |
516516+--
517517+-- >>> setStreet fred "Some Other St"
518518+-- Person 24 "Fred" (Address "Some Other St" "Fredville" (Locality "Fredmania" "New South Fred" "Fredalia"))
519519+--
520520+-- >>> setStreet mary "Some Other St"
521521+-- Person 28 "Mary" (Address "Some Other St" "Maryland" (Locality "Mary Mary" "Western Mary" "Maristan"))
522522+setStreet ::
523523+ Person
524524+ -> String
525525+ -> Person
526526+setStreet =
527527+ error "todo: setStreet"
528528+529529+-- |
530530+--
531531+-- >>> getAgeAndCountry (fred, maryLocality)
532532+-- (24,"Maristan")
533533+--
534534+-- >>> getAgeAndCountry (mary, fredLocality)
535535+-- (28,"Fredalia")
536536+getAgeAndCountry ::
537537+ (Person, Locality)
538538+ -> (Int, String)
539539+getAgeAndCountry =
540540+ error "todo: getAgeAndCountry"
541541+542542+-- |
543543+--
544544+-- >>> setCityAndLocality (fred, maryAddress) ("Some Other City", fredLocality)
545545+-- (Person 24 "Fred" (Address "15 Fred St" "Fredville" (Locality "Some Other City" "New South Fred" "Fredalia")),Address "83 Mary Ln" "Maryland" (Locality "Fredmania" "New South Fred" "Fredalia"))
546546+--
547547+-- >>> setCityAndLocality (mary, fredAddress) ("Some Other City", maryLocality)
548548+-- (Person 28 "Mary" (Address "83 Mary Ln" "Maryland" (Locality "Some Other City" "Western Mary" "Maristan")),Address "15 Fred St" "Fredville" (Locality "Mary Mary" "Western Mary" "Maristan"))
549549+setCityAndLocality ::
550550+ (Person, Address) -> (String, Locality) -> (Person, Address)
551551+setCityAndLocality =
552552+ error "todo: setCityAndLocality"
553553+554554+-- |
555555+--
556556+-- >>> getSuburbOrCity (Left maryAddress)
557557+-- "Maryland"
558558+--
559559+-- >>> getSuburbOrCity (Right fredLocality)
560560+-- "Fredmania"
561561+getSuburbOrCity ::
562562+ Either Address Locality
563563+ -> String
564564+getSuburbOrCity =
565565+ error "todo: getSuburbOrCity"
566566+567567+-- |
568568+--
569569+-- >>> setStreetOrState (Right maryLocality) "Some Other State"
570570+-- Right (Locality "Mary Mary" "Some Other State" "Maristan")
571571+--
572572+-- >>> setStreetOrState (Left fred) "Some Other St"
573573+-- Left (Person 24 "Fred" (Address "Some Other St" "Fredville" (Locality "Fredmania" "New South Fred" "Fredalia")))
574574+setStreetOrState ::
575575+ Either Person Locality
576576+ -> String
577577+ -> Either Person Locality
578578+setStreetOrState =
579579+ error "todo: setStreetOrState"
580580+581581+-- |
582582+--
583583+-- >>> modifyCityUppercase fred
584584+-- Person 24 "Fred" (Address "15 Fred St" "Fredville" (Locality "FREDMANIA" "New South Fred" "Fredalia"))
585585+--
586586+-- >>> modifyCityUppercase mary
587587+-- Person 28 "Mary" (Address "83 Mary Ln" "Maryland" (Locality "MARY MARY" "Western Mary" "Maristan"))
588588+modifyCityUppercase ::
589589+ Person
590590+ -> Person
591591+modifyCityUppercase =
592592+ error "todo: modifyCityUppercase"