-
Notifications
You must be signed in to change notification settings - Fork 53
/
Copy pathErasable.hs
46 lines (40 loc) · 1.43 KB
/
Erasable.hs
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
-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Custom extension of 'Semigroup' to 'Monoid' that adds identity +
-- annihilator elements.
module Swarm.Util.Erasable where
-- | Extend a semigroup to a monoid by adding an identity ('ENothing') /and/ an
-- annihilator ('EErase'). That is,
--
-- * @ENothing <> e = e <> ENothing = e@
-- * @EErase <> e = e <> EErase = EErase@
--
-- This allows us to "erase" previous values by combining with
-- 'EErase'. The 'erasableToMaybe' function turns an 'Erasable'
-- into a 'Maybe' by collapsing 'ENothing' and 'EErase' both back
-- into 'Nothing'.
data Erasable e = ENothing | EErase | EJust e
deriving (Show, Eq, Ord, Functor)
instance Semigroup e => Semigroup (Erasable e) where
ENothing <> e = e
e <> ENothing = e
EErase <> _ = EErase
_ <> EErase = EErase
EJust e1 <> EJust e2 = EJust (e1 <> e2)
instance Semigroup e => Monoid (Erasable e) where
mempty = ENothing
-- | Generic eliminator for 'Erasable' values.
erasable :: a -> a -> (e -> a) -> Erasable e -> a
erasable x y z = \case
ENothing -> x
EErase -> y
EJust e -> z e
-- | Convert an 'Erasable' value to 'Maybe', turning both 'ENothing'
-- and 'EErase' into 'Nothing'.
erasableToMaybe :: Erasable e -> Maybe e
erasableToMaybe = erasable Nothing Nothing Just
-- | Inject a 'Maybe' value into 'Erasable' using 'ENothing' and
-- 'EJust'.
maybeToErasable :: Maybe e -> Erasable e
maybeToErasable = maybe ENothing EJust