···1616to study the history of lenses, then build up to the most recent theories, it is
1717best to start at the `Lets.GetSetLens` module. If you wish to derive the
1818structure of lenses from first principles, then derive the more modern theories,
1919-start at the `Lets.Lens.Lens` module.
1919+start at the `Lets.Lens` module.
20202121Exercises can be recognised by filling in a function body that has a placeholder
2222of `error "todo: <function-name>"`.
···4949described by Twan van Laarhoven. This representation also introduces a
5050generalisation of lenses to permit *polymorphic update* of structures.
51515252-##### `Lets.Lens.Lens`
5252+##### `Lets.Lens`
53535454This series of exercises starts at first principles to derive the concept of a
5555lens, as it was first described by Twan van Laarhoven. The derivation then goes
···11+{-# LANGUAGE RankNTypes #-}
22+13module Lets.Lens (
22- module L
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
374) where
47555-import Lets.Lens.Choice as L
66-import Lets.Lens.Lens as L
77-import Lets.Lens.Profunctor as L
7676+import Control.Applicative(Applicative((<*>), pure))
7777+import Data.Bool(bool)
7878+import Data.Char(toUpper)
7979+import Data.Foldable(Foldable(foldMap))
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(traverse))
8686+import Lets.Data(AlongsideLeft(AlongsideLeft, getAlongsideLeft), AlongsideRight(AlongsideRight, getAlongsideRight), Identity(Identity, getIdentity), Const(Const, getConst), Tagged(Tagged, getTagged), IntOr(IntOrIs, IntOrIsNot), IntAnd(IntAnd), Person(Person), Locality(Locality), Address(Address))
8787+import Lets.Choice(Choice(left, right))
8888+import Lets.Profunctor(Profunctor(dimap))
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"
···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((<*>), pure))
7777-import Data.Bool(bool)
7878-import Data.Char(toUpper)
7979-import Data.Foldable(Foldable(foldMap))
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(traverse))
8686-import Lets.Data(AlongsideLeft(AlongsideLeft, getAlongsideLeft), AlongsideRight(AlongsideRight, getAlongsideRight), Identity(Identity, getIdentity), Const(Const, getConst), Tagged(Tagged, getTagged), IntOr(IntOrIs, IntOrIsNot), IntAnd(IntAnd), Person(Person), Locality(Locality), Address(Address))
8787-import Lets.Lens.Choice(Choice(left, right))
8888-import Lets.Lens.Profunctor(Profunctor(dimap))
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 f =
114114- getIdentity . traverse (Identity . f)
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 t f =
123123- getIdentity . t (Identity . f)
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- over traverse
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 t f =
146146- Identity . t (getIdentity . f)
147147-148148-mapped ::
149149- Functor f =>
150150- Set (f a) (f b) a b
151151-mapped =
152152- sets fmap
153153-154154-set ::
155155- Set s t a b
156156- -> s
157157- -> b
158158- -> t
159159-set t s b =
160160- over t (const b) s
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 f =
173173- getConst . traverse (Const . f)
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 t f =
182182- getConst . t (Const . f)
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- foldMapOf traverse
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 t f =
209209- Const . t (getConst . f)
210210-211211-folded ::
212212- Foldable f =>
213213- Fold (f a) (f a) a a
214214-folded =
215215- folds foldMap
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 t =
230230- getConst . t Const
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 f (a, b) =
246246- (,) <$> f a <*> f b
247247-248248--- | Traverse the left side of @Either@.
249249-traverseLeft ::
250250- Traversal (Either a x) (Either b x) a b
251251-traverseLeft f (Left a) =
252252- Left <$> f a
253253-traverseLeft _ (Right x) =
254254- pure (Right x)
255255-256256--- | Traverse the right side of @Either@.
257257-traverseRight ::
258258- Traversal (Either x a) (Either x b) a b
259259-traverseRight _ (Left x) =
260260- pure (Left x)
261261-traverseRight f (Right a) =
262262- Right <$> f a
263263-264264-type Traversal' a b =
265265- Traversal a a b b
266266-267267-----
268268-269269--- | @Const r@ is @Applicative@, if @Monoid r@, however, without the @Monoid@
270270--- constraint (as in @Get@), the only shared abstraction between @Identity@ and
271271--- @Const r@ is @Functor@.
272272---
273273--- Consequently, we arrive at our lens derivation:
274274-type Lens s t a b =
275275- forall f.
276276- Functor f =>
277277- (a -> f b)
278278- -> s
279279- -> f t
280280-281281-----
282282-283283--- | A prism is a less specific type of traversal.
284284-type Prism s t a b =
285285- forall p f.
286286- (Choice p, Applicative f) =>
287287- p a (f b)
288288- -> p s (f t)
289289-290290-_Left ::
291291- Prism (Either a x) (Either b x) a b
292292-_Left =
293293- dimap (either Right (Left . Right)) (either pure (fmap Left)) . right
294294-295295-_Right ::
296296- Prism (Either x a) (Either x b) a b
297297-_Right =
298298- dimap (either (Left . Left) Right) (either pure (fmap Right)) . right
299299-300300-prism ::
301301- (b -> t)
302302- -> (s -> Either t a)
303303- -> Prism s t a b
304304-prism to fr =
305305- dimap fr (either pure (fmap to)) . right
306306-307307-_Just ::
308308- Prism (Maybe a) (Maybe b) a b
309309-_Just =
310310- prism
311311- Just
312312- (maybe (Left Nothing) Right)
313313-314314-_Nothing ::
315315- Prism (Maybe a) (Maybe a) () ()
316316-_Nothing =
317317- prism
318318- (\() -> Nothing)
319319- (maybe (Right ()) (Left . Just))
320320-321321-setP ::
322322- Prism s t a b
323323- -> s
324324- -> Either t a
325325-setP p =
326326- either Right Left . p Left
327327-328328-getP ::
329329- Prism s t a b
330330- -> b
331331- -> t
332332-getP p =
333333- getIdentity . getTagged . p . Tagged . Identity
334334-335335-type Prism' a b =
336336- Prism a a b b
337337-338338-----
339339-340340--- |
341341---
342342--- >>> modify fstL (+1) (0 :: Int, "abc")
343343--- (1,"abc")
344344---
345345--- >>> modify sndL (+1) ("abc", 0 :: Int)
346346--- ("abc",1)
347347---
348348--- prop> let types = (x :: Int, y :: String) in modify fstL id (x, y) == (x, y)
349349---
350350--- prop> let types = (x :: Int, y :: String) in modify sndL id (x, y) == (x, y)
351351-modify ::
352352- Lens s t a b
353353- -> (a -> b)
354354- -> s
355355- -> t
356356-modify r f =
357357- getIdentity . r (Identity . f)
358358-359359--- | An alias for @modify@.
360360-(%~) ::
361361- Lens s t a b
362362- -> (a -> b)
363363- -> s
364364- -> t
365365-(%~) =
366366- modify
367367-368368-infixr 4 %~
369369-370370--- |
371371---
372372--- >>> fstL .~ 1 $ (0 :: Int, "abc")
373373--- (1,"abc")
374374---
375375--- >>> sndL .~ 1 $ ("abc", 0 :: Int)
376376--- ("abc",1)
377377---
378378--- prop> let types = (x :: Int, y :: String) in set fstL (x, y) z == (fstL .~ z $ (x, y))
379379---
380380--- prop> let types = (x :: Int, y :: String) in set sndL (x, y) z == (sndL .~ z $ (x, y))
381381-(.~) ::
382382- Lens s t a b
383383- -> b
384384- -> s
385385- -> t
386386-(.~) l =
387387- modify l . const
388388-389389-infixl 5 .~
390390-391391--- |
392392---
393393--- >>> fmodify fstL (+) (5 :: Int, "abc") 8
394394--- (13,"abc")
395395---
396396--- >>> fmodify fstL (\n -> bool Nothing (Just (n * 2)) (even n)) (10, "abc")
397397--- Just (20,"abc")
398398---
399399--- >>> fmodify fstL (\n -> bool Nothing (Just (n * 2)) (even n)) (11, "abc")
400400--- Nothing
401401-fmodify ::
402402- Functor f =>
403403- Lens s t a b
404404- -> (a -> f b)
405405- -> s
406406- -> f t
407407-fmodify l =
408408- l
409409-410410--- |
411411---
412412--- >>> fstL |= Just 3 $ (7, "abc")
413413--- Just (3,"abc")
414414---
415415--- >>> (fstL |= (+1) $ (3, "abc")) 17
416416--- (18,"abc")
417417-(|=) ::
418418- Functor f =>
419419- Lens s t a b
420420- -> f b
421421- -> s
422422- -> f t
423423-(|=) l =
424424- fmodify l . const
425425-426426-infixl 5 |=
427427-428428--- |
429429---
430430--- >>> modify fstL (*10) (3, "abc")
431431--- (30,"abc")
432432-fstL ::
433433- Lens (a, x) (b, x) a b
434434-fstL p (x, y) =
435435- fmap (\x' -> (x', y)) (p x)
436436-437437--- |
438438---
439439--- >>> modify sndL (++ "def") (13, "abc")
440440--- (13,"abcdef")
441441-sndL ::
442442- Lens (x, a) (x, b) a b
443443-sndL p (x, y) =
444444- fmap (\y' -> (x, y')) (p y)
445445-446446--- |
447447---
448448--- >>> get (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d']))
449449--- Just 'c'
450450---
451451--- >>> get (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d']))
452452--- Nothing
453453---
454454--- >>> set (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) (Just 'X')
455455--- fromList [(1,'a'),(2,'b'),(3,'X'),(4,'d')]
456456---
457457--- >>> set (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) (Just 'X')
458458--- fromList [(1,'a'),(2,'b'),(3,'c'),(4,'d'),(33,'X')]
459459---
460460--- >>> set (mapL 3) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) Nothing
461461--- fromList [(1,'a'),(2,'b'),(4,'d')]
462462---
463463--- >>> set (mapL 33) (Map.fromList (map (\c -> (ord c - 96, c)) ['a'..'d'])) Nothing
464464--- fromList [(1,'a'),(2,'b'),(3,'c'),(4,'d')]
465465-mapL ::
466466- Ord k =>
467467- k
468468- -> Lens (Map k v) (Map k v) (Maybe v) (Maybe v)
469469-mapL k p m =
470470- let z = Map.lookup k m
471471- in fmap (\y -> case y of
472472- Just v -> Map.insert k v m
473473- Nothing -> case z of
474474- Just _ -> Map.delete k m
475475- Nothing -> m) (p z)
476476-477477--- |
478478---
479479--- >>> get (setL 3) (Set.fromList [1..5])
480480--- True
481481---
482482--- >>> get (setL 33) (Set.fromList [1..5])
483483--- False
484484---
485485--- >>> set (setL 3) (Set.fromList [1..5]) True
486486--- fromList [1,2,3,4,5]
487487---
488488--- >>> set (setL 3) (Set.fromList [1..5]) False
489489--- fromList [1,2,4,5]
490490---
491491--- >>> set (setL 33) (Set.fromList [1..5]) True
492492--- fromList [1,2,3,4,5,33]
493493---
494494--- >>> set (setL 33) (Set.fromList [1..5]) False
495495--- fromList [1,2,3,4,5]
496496-setL ::
497497- Ord k =>
498498- k
499499- -> Lens (Set.Set k) (Set.Set k) Bool Bool
500500-setL k =
501501- (\p s -> fmap (\b -> bool Set.delete Set.insert b k s) (p (Set.member k s)))
502502-503503--- |
504504---
505505--- >>> get (compose fstL sndL) ("abc", (7, "def"))
506506--- 7
507507---
508508--- >>> set (compose fstL sndL) ("abc", (7, "def")) 8
509509--- ("abc",(8,"def"))
510510-compose ::
511511- Lens s t a b
512512- -> Lens q r s t
513513- -> Lens q r a b
514514-compose r1 r2 =
515515- r2 . r1
516516-517517--- | An alias for @compose@.
518518-(|.) ::
519519- Lens s t a b
520520- -> Lens q r s t
521521- -> Lens q r a b
522522-(|.) =
523523- compose
524524-525525-infixr 9 |.
526526-527527--- |
528528---
529529--- >>> get identity 3
530530--- 3
531531---
532532--- >>> set identity 3 4
533533--- 4
534534-identity ::
535535- Lens a b a b
536536-identity =
537537- id
538538-539539--- |
540540---
541541--- >>> get (product fstL sndL) (("abc", 3), (4, "def"))
542542--- ("abc","def")
543543---
544544--- >>> set (product fstL sndL) (("abc", 3), (4, "def")) ("ghi", "jkl")
545545--- (("ghi",3),(4,"jkl"))
546546-product ::
547547- Lens s t a b
548548- -> Lens q r c d
549549- -> Lens (s, q) (t, r) (a, c) (b, d)
550550-product r1 r2 p (a, c) =
551551- getAlongsideRight (r2 (\b2 -> AlongsideRight (
552552- getAlongsideLeft (r1 (\b1 -> AlongsideLeft (
553553- p (b1,b2))) a))) c)
554554-555555--- | An alias for @product@.
556556-(***) ::
557557- Lens s t a b
558558- -> Lens q r c d
559559- -> Lens (s, q) (t, r) (a, c) (b, d)
560560-(***) =
561561- product
562562-563563-infixr 3 ***
564564-565565--- |
566566---
567567--- >>> get (choice fstL sndL) (Left ("abc", 7))
568568--- "abc"
569569---
570570--- >>> get (choice fstL sndL) (Right ("abc", 7))
571571--- 7
572572---
573573--- >>> set (choice fstL sndL) (Left ("abc", 7)) "def"
574574--- Left ("def",7)
575575---
576576--- >>> set (choice fstL sndL) (Right ("abc", 7)) 8
577577--- Right ("abc",8)
578578-choice ::
579579- Lens s t a b
580580- -> Lens q r a b
581581- -> Lens (Either s q) (Either t r) a b
582582-choice r1 r2 =
583583-584584- (\p e -> case e of
585585- Left a -> fmap Left (r1 p a)
586586- Right b -> fmap Right (r2 p b))
587587-588588--- | An alias for @choice@.
589589-(|||) ::
590590- Lens s t a b
591591- -> Lens q r a b
592592- -> Lens (Either s q) (Either t r) a b
593593-(|||) =
594594- choice
595595-596596-infixr 2 |||
597597-598598-----
599599-600600-type Lens' a b =
601601- Lens a a b b
602602-603603-cityL ::
604604- Lens' Locality String
605605-cityL p (Locality c t y) =
606606- fmap (\c' -> Locality c' t y) (p c)
607607-608608-stateL ::
609609- Lens' Locality String
610610-stateL p (Locality c t y) =
611611- fmap (\t' -> Locality c t' y) (p t)
612612-613613-countryL ::
614614- Lens' Locality String
615615-countryL p (Locality c t y) =
616616- fmap (\y' -> Locality c t y') (p y)
617617-618618-streetL ::
619619- Lens' Address String
620620-streetL p (Address t s l) =
621621- fmap (\t' -> Address t' s l) (p t)
622622-623623-suburbL ::
624624- Lens' Address String
625625-suburbL p (Address t s l) =
626626- fmap (\s' -> Address t s' l) (p s)
627627-628628-localityL ::
629629- Lens' Address Locality
630630-localityL p (Address t s l) =
631631- fmap (\l' -> Address t s l') (p l)
632632-633633-ageL ::
634634- Lens' Person Int
635635-ageL p (Person a n d) =
636636- fmap (\a' -> Person a' n d) (p a)
637637-638638-nameL ::
639639- Lens' Person String
640640-nameL p (Person a n d) =
641641- fmap (\n' -> Person a n' d) (p n)
642642-643643-addressL ::
644644- Lens' Person Address
645645-addressL p (Person a n d) =
646646- fmap (\d' -> Person a n d') (p d)
647647-648648-intAndIntL ::
649649- Lens' (IntAnd a) Int
650650-intAndIntL p (IntAnd n a) =
651651- fmap (\n' -> IntAnd n' a) (p n)
652652-653653--- lens for polymorphic update
654654-intAndL ::
655655- Lens (IntAnd a) (IntAnd b) a b
656656-intAndL p (IntAnd n a) =
657657- fmap (\a' -> IntAnd n a') (p a)
658658-659659--- |
660660---
661661--- >>> get (suburbL |. addressL) fred
662662--- "Fredville"
663663---
664664--- >>> get (suburbL |. addressL) mary
665665--- "Maryland"
666666-getSuburb ::
667667- Person
668668- -> String
669669-getSuburb =
670670- get (suburbL |. addressL)
671671-672672--- |
673673---
674674--- >>> setStreet fred "Some Other St"
675675--- Person 24 "Fred" (Address "Some Other St" "Fredville" (Locality "Fredmania" "New South Fred" "Fredalia"))
676676---
677677--- >>> setStreet mary "Some Other St"
678678--- Person 28 "Mary" (Address "Some Other St" "Maryland" (Locality "Mary Mary" "Western Mary" "Maristan"))
679679-setStreet ::
680680- Person
681681- -> String
682682- -> Person
683683-setStreet =
684684- set (streetL |. addressL)
685685-686686--- |
687687---
688688--- >>> getAgeAndCountry (fred, maryLocality)
689689--- (24,"Maristan")
690690---
691691--- >>> getAgeAndCountry (mary, fredLocality)
692692--- (28,"Fredalia")
693693-getAgeAndCountry ::
694694- (Person, Locality)
695695- -> (Int, String)
696696-getAgeAndCountry =
697697- get (ageL *** countryL)
698698-699699--- |
700700---
701701--- >>> setCityAndLocality (fred, maryAddress) ("Some Other City", fredLocality)
702702--- (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"))
703703---
704704--- >>> setCityAndLocality (mary, fredAddress) ("Some Other City", maryLocality)
705705--- (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"))
706706-setCityAndLocality ::
707707- (Person, Address) -> (String, Locality) -> (Person, Address)
708708-setCityAndLocality =
709709- set (cityL |. localityL |. addressL *** localityL)
710710-711711--- |
712712---
713713--- >>> getSuburbOrCity (Left maryAddress)
714714--- "Maryland"
715715---
716716--- >>> getSuburbOrCity (Right fredLocality)
717717--- "Fredmania"
718718-getSuburbOrCity ::
719719- Either Address Locality
720720- -> String
721721-getSuburbOrCity =
722722- get (suburbL ||| cityL)
723723-724724--- |
725725---
726726--- >>> setStreetOrState (Right maryLocality) "Some Other State"
727727--- Right (Locality "Mary Mary" "Some Other State" "Maristan")
728728---
729729--- >>> setStreetOrState (Left fred) "Some Other St"
730730--- Left (Person 24 "Fred" (Address "Some Other St" "Fredville" (Locality "Fredmania" "New South Fred" "Fredalia")))
731731-setStreetOrState ::
732732- Either Person Locality
733733- -> String
734734- -> Either Person Locality
735735-setStreetOrState =
736736- set (streetL |. addressL ||| stateL)
737737-738738--- |
739739---
740740--- >>> modifyCityUppercase fred
741741--- Person 24 "Fred" (Address "15 Fred St" "Fredville" (Locality "FREDMANIA" "New South Fred" "Fredalia"))
742742---
743743--- >>> modifyCityUppercase mary
744744--- Person 28 "Mary" (Address "83 Mary Ln" "Maryland" (Locality "MARY MARY" "Western Mary" "Maristan"))
745745-modifyCityUppercase ::
746746- Person
747747- -> Person
748748-modifyCityUppercase =
749749- cityL |. localityL |. addressL %~ map toUpper
750750-751751--- |
752752---
753753--- >>> modifyIntAndLengthEven (IntAnd 10 "abc")
754754--- IntAnd 10 False
755755---
756756--- >>> modifyIntAndLengthEven (IntAnd 10 "abcd")
757757--- IntAnd 10 True
758758-modifyIntAndLengthEven ::
759759- IntAnd [a]
760760- -> IntAnd Bool
761761-modifyIntAndLengthEven =
762762- intAndL %~ even . length
763763-764764-----
765765-766766--- |
767767---
768768--- >>> over traverseLocality (map toUpper) (Locality "abc" "def" "ghi")
769769--- Locality "ABC" "DEF" "GHI"
770770-traverseLocality ::
771771- Traversal' Locality String
772772-traverseLocality f (Locality c t y) =
773773- Locality <$> f c <*> f t <*> f y
774774-775775--- |
776776---
777777--- >>> over intOrIntP (*10) (IntOrIs 3)
778778--- IntOrIs 30
779779---
780780--- >>> over intOrIntP (*10) (IntOrIsNot "abc")
781781--- IntOrIsNot "abc"
782782-intOrIntP ::
783783- Prism' (IntOr a) Int
784784-intOrIntP =
785785- prism
786786- IntOrIs
787787- (\i -> case i of
788788- IntOrIs n -> Right n
789789- IntOrIsNot a -> Left (IntOrIsNot a))
790790-791791-intOrP ::
792792- Prism (IntOr a) (IntOr b) a b
793793-intOrP =
794794- prism
795795- IntOrIsNot
796796- (\i -> case i of
797797- IntOrIs n -> Left (IntOrIs n)
798798- IntOrIsNot a -> Right a)
799799-800800--- |
801801---
802802--- >> over intOrP (even . length) (IntOrIsNot "abc")
803803--- IntOrIsNot False
804804---
805805--- >>> over intOrP (even . length) (IntOrIsNot "abcd")
806806--- IntOrIsNot True
807807---
808808--- >>> over intOrP (even . length) (IntOrIs 10)
809809--- IntOrIs 10
810810-intOrLengthEven ::
811811- IntOr [a]
812812- -> IntOr Bool
813813-intOrLengthEven =
814814- over intOrP (even . length)