File: Functors.hs

package info (click to toggle)
haskell-ghc-exactprint 1.7.1.0-1
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,044 kB
  • sloc: haskell: 32,076; makefile: 7
file content (530 lines) | stat: -rw-r--r-- 16,654 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
-- | Types are great. Lifting them into some sort of applicative functor makes
-- them even better. This module is an homage to our favorite applicatives, and
-- to the semigroups with which they are instrinsically connected.

{-# LANGUAGE NoImplicitPrelude #-} -- Prelude is bad
{-# LANGUAGE DeriveFunctor     #-} -- Writing Functor instances is boring

module Acme.Functors
    (
    -- * Lifted-but-why
      LiftedButWhy (..)

    -- * Or-not
    , OrNot (..)

    -- * Two
    , Two (..)

    -- * Any-number-of
    , AnyNumberOf (..), (~~)

    -- * One-or-more
    , OneOrMore (..)

    -- * Also-extra-thing
    , Also (..)

    -- * Or-instead-other-thing
    , OrInstead (..)

    -- * Or-instead-other-thing ("first" variant)
    , OrInsteadFirst (..)

    -- * Determined-by-parameter
    , DeterminedBy (..)

    ) where

import Acme.Functors.Classes


--------------------------------------------------------------------------------
--  Lifted-but-why
--------------------------------------------------------------------------------

-- | __@LiftedButWhy@__ is a boring functor that just has one value and no other
-- structure or interesting properties.

data LiftedButWhy a =

    LiftedButWhy a
    -- ^ A value that has been lifted for some damned reason.
    --
    -- ... Okay, to be honest, this one is /nobody's/ favorite, but it is
    -- included here for completeness.

    deriving (Eq, Functor, Show)

-- | > pure = LiftedButWhy
-- >
-- > LiftedButWhy f <*> LiftedButWhy a = LiftedButWhy (f a)

instance Applicative LiftedButWhy where

    pure = LiftedButWhy

    LiftedButWhy f <*> LiftedButWhy a = LiftedButWhy (f a)

-- | > LiftedButWhy a >>= f = f a
instance Monad LiftedButWhy where

    LiftedButWhy a >>= f = f a

-- | > LiftedButWhy x <> LiftedButWhy y = LiftedButWhy (x <> y)

instance Semigroup a => Semigroup (LiftedButWhy a) where

    LiftedButWhy x <> LiftedButWhy y = LiftedButWhy (x <> y)

-- | > mempty = LiftedButWhy mempty

instance Monoid a => Monoid (LiftedButWhy a) where

    mempty = LiftedButWhy mempty


--------------------------------------------------------------------------------
--  Or-not
--------------------------------------------------------------------------------

-- | __@OrNot@__ is somehow slightly more interesting than @LiftedButWhy@, even
-- though it may actually contain /less/. Instead of a value, there might /not/
-- be a value.
--
-- When you combine stuff with @(\<*\>)@ or @(\<\>)@, all of the values need to
-- be present. If any of them are absent, the whole expression evaluates to
-- @Nope@.

data OrNot a = ActuallyYes a -- ^ Some normal value.
             | Nope          -- ^ Chuck Testa.
    deriving (Eq, Functor, Show)

-- | If you have a function @f@ that might not actually be there, and a value
-- @a@ that might not actually be there, lifted application @(\<*\>)@ gives you
-- @f a@ only if both of them are actually there.
--
-- > pure = ActuallyYes
-- >
-- > ActuallyYes f <*> ActuallyYes a = ActuallyYes (f a)
-- > _             <*> _             = Nope

instance Applicative OrNot where

    pure = ActuallyYes

    ActuallyYes f <*> ActuallyYes a = ActuallyYes (f a)
    _             <*> _             = Nope

instance Monad OrNot where

    ActuallyYes a  >>= f = f a
    Nope           >>= _ = Nope

-- | If you have value @a@ that may not actually be there, and another value
-- @a'@ that might not actually be there, the lifted semigroup operation
-- @(\<\>)@ gives you @a \<\> a'@ only if both of them are actually there.
--
-- > ActuallyYes a <> ActuallyYes a' = ActuallyYes (a <> a')
-- > _             <> _              = Nope

instance Semigroup a => Semigroup (OrNot a) where

    ActuallyYes a <> ActuallyYes a' = ActuallyYes (a <> a')
    _             <> _              = Nope

-- | > mempty = ActuallyYes mempty

instance Monoid a => Monoid (OrNot a) where

    mempty = ActuallyYes mempty


--------------------------------------------------------------------------------
--  Two
--------------------------------------------------------------------------------

-- | __@Two@__ is /two/ values. Yep. Just two values.

data Two a = Two { firstOfTwo  :: a -- ^ One value.
                 , secondOfTwo :: a -- ^ Another value.
                 }
    deriving (Eq, Functor, Show)

-- | If you have two functions @f@ and @g@ and two values @a@ and @a'@, then you
-- can apply them with @(\<*\>)@ to get two results @f a@ and @g a'@.
--
-- > pure a = Two a a
-- >
-- > Two f g <*> Two a a' = Two (f a) (g a')

instance Applicative Two where

    pure a = Two a a

    Two f g <*> Two a a' = Two (f a) (g a')

-- | > Two x y <> Two x' y' = Two (x <> x') (y <> y')

instance Semigroup a => Semigroup (Two a) where

    Two x y <> Two x' y' = Two (x <> x') (y <> y')

-- | > mempty = Two mempty mempty

instance Monoid a => Monoid (Two a) where

    mempty = Two mempty mempty


--------------------------------------------------------------------------------
--  Any-number-of
--------------------------------------------------------------------------------

-- | __@AnyNumberOf@__ starts to get exciting. Any number of values you want.
-- Zero... one ... two ... three ... four ... five ... The possibilities are
-- /truly/ endless.

data AnyNumberOf a =

    OneAndMaybeMore a (AnyNumberOf a)
    -- ^ One value, and maybe even more after that!

    | ActuallyNone -- ^ Oh. Well this is less fun.

    deriving (Eq, Functor, Show)

-- | Alias for 'OneAndMaybeMore' which provides some brevity.

(~~) :: a -> AnyNumberOf a -> AnyNumberOf a
(~~) = OneAndMaybeMore

infixr 5 ~~

-- | You can use this to apply any number of functions to any number of
-- arguments.
--
-- > pure a = OneAndMaybeMore a ActuallyNone
-- >
-- > OneAndMaybeMore f fs <*> OneAndMaybeMore x xs =
-- >     OneAndMaybeMore (f x) (fs <*> xs)
-- > _ <*> _ = ActuallyNone
--
-- Example:
--
-- >     ( (+ 1) ~~ (* 2) ~~ (+ 5) ~~       ActuallyNone )
-- > <*> (    1  ~~    6  ~~    4  ~~ 37 ~~ ActuallyNone )
-- >  =  (    7  ~~   12  ~~    9  ~~       ActuallyNone )
--
-- This example demonstrates how when there are more arguments than functions,
-- any excess arguments (in this case, the @37@) are ignored.

instance Applicative AnyNumberOf where

    pure a = OneAndMaybeMore a ActuallyNone

    OneAndMaybeMore f fs <*> OneAndMaybeMore x xs =
        OneAndMaybeMore (f x) (fs <*> xs)
    _ <*> _ = ActuallyNone

-- | The operation of combining some number of @a@ with some other number of @a@
-- is sometimes referred to as /zipping/.
--
-- > OneAndMaybeMore x xs <> OneAndMaybeMore y ys =
-- >     OneAndMaybeMore (x <> y) (xs <> ys)
-- > _ <> _ = ActuallyNone

instance Semigroup a => Semigroup (AnyNumberOf a) where

    OneAndMaybeMore x xs <> OneAndMaybeMore y ys =
        OneAndMaybeMore (x <> y) (xs <> ys)
    _ <> _ = ActuallyNone

-- | > mempty = mempty ~~ mempty

instance Monoid a => Monoid (AnyNumberOf a) where

    mempty = mempty ~~ mempty


--------------------------------------------------------------------------------
--  One-or-more
--------------------------------------------------------------------------------

-- | __@OneOrMore@__ is more restrictive than AnyNumberOf, yet somehow actually
-- /more/ interesting, because it excludes that dull situation where there
-- aren't any values at all.

data OneOrMore a = OneOrMore
    { theFirstOfMany :: a -- ^ Definitely at least this one.
    , possiblyMore :: AnyNumberOf a -- ^ And perhaps others.
    } deriving (Eq, Functor, Show)

-- | > pure a = OneOrMore a ActuallyNone
-- >
-- > OneOrMore f fs <*> OneOrMore x xs = OneOrMore (f x) (fs <*> xs)

instance Applicative OneOrMore where

    pure a = OneOrMore a ActuallyNone

    OneOrMore f fs <*> OneOrMore x xs = OneOrMore (f x) (fs <*> xs)

-- |
-- > OneOrMore a more <> OneOrMore a' more' =
-- >     OneOrMore a (more <> OneAndMaybeMore a' more')

instance Semigroup a => Semigroup (OneOrMore a) where

    OneOrMore a more <> OneOrMore a' more' =
        OneOrMore a (more <> OneAndMaybeMore a' more')

-- | > mempty = OneOrMore mempty ActuallyNone

instance Monoid a => Monoid (OneOrMore a) where

    mempty = OneOrMore mempty ActuallyNone


--------------------------------------------------------------------------------
--  Also-extra-thing
--------------------------------------------------------------------------------

-- | __@Also extraThing@__ is a functor in which each value has an @extraThing@
-- of some other type that tags along with it.

data (Also extraThing) a = Also
    { withoutExtraThing :: a          -- ^ A value.
    , theExtraThing     :: extraThing -- ^ An additional thing that tags along.
    }
    deriving (Eq, Functor, Show)

-- | Dragging the @extraThing@ along can be a bit of a burden. It prevents @Also
-- extraThing@ from being an applicative functor — unless the @extraThing@ can
-- pull its weight by bringing a monoid to the table.
--
-- > pure = (`Also` mempty)
-- >
-- > (f `Also` extra1) <*> (a `Also` extra2) = f a
-- >                                           `Also` (extra1 <> extra2)

instance Monoid extraThing => Applicative (Also extraThing) where

    pure = (`Also` mempty)

    (f `Also` extra1) <*> (a `Also` extra2) = f a
                                              `Also` (extra1 <> extra2)

-- |
-- > (a `Also` extra1) <> (a' `Also` extra2) = (a <> a')
-- >                                           `Also` (extra1 <> extra2)

instance (Semigroup extraThing, Semigroup a) => Semigroup ((Also extraThing) a)
  where

    (a `Also` extra1) <> (a' `Also` extra2) = (a <> a')
                                              `Also` (extra1 <> extra2)

-- | > mempty = Also mempty mempty

instance (Monoid extraThing, Monoid a) => Monoid ((Also extraThing) a)
  where

    mempty = Also mempty mempty


--------------------------------------------------------------------------------
--  Or-instead-other-thing
--------------------------------------------------------------------------------

-- | __@OrInstead otherThing@__ is a functor in which, instead of having a
-- value, can actually just have some totally unrelated @otherThing@ instead.
--
-- When you combine stuff with @(\<*\>)@ or @(\<\>)@, all of the values need to
-- be present. If any of them are the @otherThing@ instead, then the whole
-- expression evaluates to the combination of the @otherThing@s.

data (OrInstead otherThing) a =
      NotInstead a       -- ^ Some normal value.
    | Instead otherThing -- ^ Some totally unrelated other thing.
    deriving (Eq, Functor, Show)

-- | The possibility of having an @otherThing@ obstructs this functor's ability
-- to be applicative, much like the extra thing in @Also extraThing@ does. In
-- this case, since we do not need an empty value for the @otherThing@, it needs
-- only a semigroup to be in compliance.
--
-- > pure = NotInstead
-- >
-- > NotInstead f   <*> NotInstead a   = NotInstead (f a)
-- > Instead other1 <*> Instead other2 = Instead (other1 <> other2)
-- > Instead other  <*> _              = Instead other
-- > _              <*> Instead other  = Instead other

instance Semigroup otherThing => Applicative (OrInstead otherThing) where

    pure = NotInstead

    NotInstead f   <*> NotInstead a   = NotInstead (f a)
    Instead other1 <*> Instead other2 = Instead (other1 <> other2)
    Instead other  <*> _              = Instead other
    _              <*> Instead other  = Instead other

-- |
-- > NotInstead a   <> NotInstead a'  = NotInstead (a <> a')
-- > Instead other1 <> Instead other2 = Instead (other1 <> other2)
-- > Instead other  <> _              = Instead other
-- > _              <> Instead other  = Instead other

instance (Semigroup otherThing, Semigroup a) =>
  Semigroup ((OrInstead otherThing) a) where

    NotInstead a   <> NotInstead a'  = NotInstead (a <> a')
    Instead other1 <> Instead other2 = Instead (other1 <> other2)
    Instead other  <> _              = Instead other
    _              <> Instead other  = Instead other

-- > mempty = NotInstead mempty

instance (Semigroup otherThing, Monoid a) => Monoid ((OrInstead otherThing) a)
  where

    mempty = NotInstead mempty


--------------------------------------------------------------------------------
--  Or-instead-first-thing
--------------------------------------------------------------------------------

-- | __@OrInsteadFirst otherThing@__ looks a lot like @OrInstead otherThing@,
-- but it manages to always be an applicative functor — and even a monad too —
-- by handling the @otherThing@s a bit more hamfistedly.
--
-- When you combine stuff with @(\<*\>)@ or @(\<\>)@, all of the values need to
-- be present. If any of them are the @otherThing@ instead, then the whole
-- expression evaluates to the /first/ @otherThing@ encountered, ignoring any
-- additional @otherThings@ that may subsequently pop up

data (OrInsteadFirst otherThing) a =
      NotInsteadFirst a       -- ^ Some normal value.
    | InsteadFirst otherThing -- ^ Some totally unrelated other thing.
    deriving (Eq, Functor, Show)

-- |
-- > pure = NotInsteadFirst
-- >
-- > NotInsteadFirst f  <*> NotInsteadFirst a  = NotInsteadFirst (f a)
-- > InsteadFirst other <*> _                  = InsteadFirst other
-- > _                  <*> InsteadFirst other = InsteadFirst other

instance Applicative (OrInsteadFirst otherThing) where

    pure = NotInsteadFirst

    NotInsteadFirst f  <*> NotInsteadFirst a  = NotInsteadFirst (f a)
    InsteadFirst other <*> _                  = InsteadFirst other
    _                  <*> InsteadFirst other = InsteadFirst other

-- |
-- > InsteadFirst other >>= _ = InsteadFirst other
-- > NotInsteadFirst a  >>= f = f a

instance Monad (OrInsteadFirst otherThing) where

    InsteadFirst other >>= _ = InsteadFirst other
    NotInsteadFirst a  >>= f = f a

-- |
-- > NotInsteadFirst a  <> NotInsteadFirst a' = NotInsteadFirst (a <> a')
-- > InsteadFirst other <> _                  = InsteadFirst other
-- > _                  <> InsteadFirst other = InsteadFirst other

instance (Semigroup otherThing, Semigroup a) =>
  Semigroup ((OrInsteadFirst otherThing) a) where

    NotInsteadFirst a  <> NotInsteadFirst a' = NotInsteadFirst (a <> a')
    InsteadFirst other <> _                  = InsteadFirst other
    _                  <> InsteadFirst other = InsteadFirst other

-- | > mempty = NotInsteadFirst mempty

instance (Semigroup otherThing, Monoid a) =>
  Monoid ((OrInsteadFirst otherThing) a) where

    mempty = NotInsteadFirst mempty


--------------------------------------------------------------------------------
--  Determined-by-parameter
--------------------------------------------------------------------------------

-- | __@DeterminedBy parameter@__ is a value that... well, we're not really sure
-- what it is. We'll find out once a @parameter@ is provided.
--
-- The mechanism for deciding /how/ the value is determined from the
-- @parameter@ is opaque; all you can do is test it with different parameters
-- and see what results. There aren't even @Eq@ or @Show@ instances, which is
-- annoying.

data DeterminedBy parameter a = Determination ((->) parameter a)
    deriving (Functor)

-- |
-- > pure a = Determination (\_ -> a)
-- >
-- > Determination f <*> Determination a = Determination (\x -> f x (a x))

instance Applicative (DeterminedBy parameter) where

    pure a = Determination (\_ -> a)

    Determination f <*> Determination a = Determination (\x -> f x (a x))

-- |
-- > Determination fa >>= ff =
-- >     Determination (\x -> let Determination f = ff (fa x) in f x)

instance Monad (DeterminedBy parameter) where

    Determination fa >>= ff =
        Determination (\x -> let Determination f = ff (fa x) in f x)

-- | > Determination f <> Determination g = Determination (\x -> f x <> g x)

instance Semigroup a => Semigroup ((DeterminedBy parameter) a) where

    Determination f <> Determination g = Determination (\x -> f x <> g x)

-- | > mempty = Determination (\_ -> mempty)

instance Monoid a => Monoid ((DeterminedBy parameter) a) where

    mempty = Determination (\_ -> mempty)


{-

--------------------------------------------------------------------------------
--  Notes
--------------------------------------------------------------------------------

LiftedButWhy is Identity.

OrNot is Maybe, but with a different semigroup and monoid.

Two doesn't have an analogue in the standard library as far as I know.

AnyNumberOf is ZipList.

OneOrMore is NonEmpty.

Also is (,), the 2-tuple.

OrInstead is AccValidation from the 'validation' package.

OrInsteadFirst is Either.

DeterminedBy is (->) also known as a function, whose functor is also known as
Reader.

-}