6

Of course the data type is not exact, but is this how (more or less) the Monoid Bool is implemented?

import Data.Monoid

data Bool' = T | F deriving (Show)

instance Monoid (Bool') where
    mempty = T
    mappend T _ = T
    mappend _ T = T
    mappend _ _ = F 

If so/not, what is the reasoning for making Bool's mappend an OR versus AND?

Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384

2 Answers2

19

There are two possible Monoid instances for Bool, so Data.Monoid has newtypes to distinguish which one we intend:

-- | Boolean monoid under conjunction.
newtype All = All { getAll :: Bool }
        deriving (Eq, Ord, Read, Show, Bounded, Generic)

instance Monoid All where
        mempty = All True
        All x `mappend` All y = All (x && y)

-- | Boolean monoid under disjunction.
newtype Any = Any { getAny :: Bool }
        deriving (Eq, Ord, Read, Show, Bounded, Generic)

instance Monoid Any where
        mempty = Any False
        Any x `mappend` Any y = Any (x || y)

Edit: There are actually four valid instances as Ørjan notes

Gabriella Gonzalez
  • 34,863
  • 3
  • 77
  • 135
  • 1
    Thank you. I'm not sure if it's a separate question entirely, but why is `newtype` used rather than `data`? Thx – Kevin Meredith Oct 27 '14 at 04:23
  • 1
    `newtype` is more efficient than `data`. Wrapping and unwrapping a newtype is free performance-wise. – Gabriella Gonzalez Oct 27 '14 at 04:29
  • 14
    There are four, actually. `(&&),(||),(==),(/=)` all are possible monoid operations. The last two aren't predefined, though. – Ørjan Johansen Oct 27 '14 at 04:34
  • Xor also forms a monoid. – alternative Oct 27 '14 at 13:27
  • @alternative Xor is the same monoid as `(/=)` – Gabriella Gonzalez Oct 27 '14 at 13:54
  • @GabrielGonzalez So? Still a monoid, and you said there are two possible instances. Xor is also an instance. – alternative Oct 27 '14 at 14:03
  • @alternative Right, I agree that there are actually four instances. – Gabriella Gonzalez Oct 27 '14 at 14:34
  • 2
    @AndrewC It looks to me like `True` is `mempty` for the `(==)` instance and `False` is `mempty` for the `(/=)` instance. Also, in this case, if one of those two `mempty` laws is satisfied the other one is too because both `(==)` and `(/=)` are commutative. – David Young Oct 27 '14 at 18:22
  • Can someone clarify what the `getAll` and `getAny` are? I have never seen the curly-bracket syntax before so if it's just a syntax thing, where could I find more information on it? – 2016rshah Sep 10 '15 at 00:46
  • 1
    @2016rshah That's known as "record syntax" and you can learn more about it [here](http://learnyouahaskell.com/making-our-own-types-and-typeclasses) in the section titled "Record syntax" – Gabriella Gonzalez Sep 10 '15 at 23:19
  • I would say they are 16 possible monoids (2^4) given the 16 possible binary operations coming from all the combinations of T/F for the outputs given four different inputs (FF,TF,FT,TT). Some of which could be useless (like all F or all T). – Ludovic Kuty Feb 04 '17 at 07:47
  • 3
    lkuty: Eight of those are ineligible because their `<>` has `T <> F /= F <> T`, which means neither `F` nor `T` is `mempty`. Two others are ineligible because their `<>` has `T <> F = F = T <> T` which means neither `F` nor `T` is `mempty`. Two others are ineligible because their `<>` has `T <> F = T = F <> F` which means neither `F` nor `T` is `mempty`. The remaining four are `&&`, `||`, `==`, and `/=`. – rampion Aug 25 '17 at 17:36
  • @ØrjanJohansen How is `(==)` a monoid? What is the identity? – Anabra May 31 '19 at 16:03
  • @Anabra: It's a `Monoid` when it's used to compare `Bool`s. The identity is `True` – Gabriella Gonzalez May 31 '19 at 22:15
5

Your provided instance isn't a monoid.

mappend F mempty
mappend F T  -- by definition of mempty
T            -- by definition of mappend

so we've proven F <> mempty === T, but for any monoid, x <> mempty === x.

The unit for Any is False, and the unit for All is True.

John L
  • 27,937
  • 4
  • 73
  • 88