## Can TimeDuration type be an instance of Semigroup and Monoid?

monoid laws
function monoid
tree monoid

In an attempt to find a quick and easy way to add different time periods, it occurred to me that I could declare them instances of Semigroup and Monoid. Are the following instantiations valid?

```data TimeDuration = S Int | M Int | H Int deriving (Show, Eq)

instance Semigroup TimeDuration where
S n1 <> S n2 = S (n1 + n2)
M n1 <> M n2 = S (60 * (n1 + n2))
H n1 <> H n2 = S (3600 * (n1 + n2))
S n1 <> M n2 = S (n1 + 60 * n2)
S n1 <> H n2 = S (n1 + 3600 * n2)
M n1 <> S n2 = S (60 * n1 + n2)
M n1 <> H n2 = S (60 * n1 + 3600 * n2)
H n1 <> S n2 = S (3600 * n1 + n2)
H n1 <> M n2 = S (3600 * n1 + 60 * n2)

instance Monoid TimeDuration where
mempty = S 0
```

Example: mconcat [S 1, M 2, M 3, S 2, H 1] == S 3903

User leftaroundabout ask me to produce more significative example. So this is a new implementation and some examples that I hope will show better the possible variety of the results of the operation (<>)

```instance Semigroup TimeDuration where
S n1 <> S n2 = S (n1 + n2)
M n1 <> M n2 = M (n1 + n2)
H n1 <> H n2 = H (n1 + n2)
S n1 <> M n2 = S (n1 + 60 * n2)
M n1 <> S n2 = S n2 <> M n1
S n1 <> H n2 = S (n1 + 3600 * n2)
H n1 <> S n2 = S n2 <> H n1
M n1 <> H n2 = M (n1 + 60 * n2)
H n1 <> M n2 = M n1 <> H n1

instance Monoid TimeDuration where
mempty = S 0
mconcat [] = S 0
mconcat xs = foldr1 (\y acc -> y <> acc) xs

-- ex. mconcat [M 2, M 3] == M 5
-- ex. mconcat [H 2, H 3] == H 5
-- ex. mconcat [M 2, M 3, S 1] == S 301
-- ex. mconcat [H 2, H 3, M 1] == M 301
-- ex. mconcat [H 2, H 3, S 1] == S 18001
```

Yeah, that's fine. It's basically equivalent to

```{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}

import GHC.Generics

newtype TimeDuration = TimeDuration {getDurationInSeconds :: Integer}
```

...with extra constructors for the special cases `TimeDuration 60`, `TimeDuration 180`... `TimeDuration 3600` etc. (which in your construction are actually redundant; you could better make simple builder-functions to do the same job).

The `AdditiveGroup` typeclass is a specialised monoid typeclass, that avoids any confusion that it might be a multiplication monoid instead – which wouldn't actually make any sense because dimension-wise, time × time doesn't match time, but for dimensionless number types like `Int` or `Double` the multiplication monoid is just as sensible as the addition one.

Because these still have an unambiguous `AdditiveGroup` instance, the `AdditiveGroup TimeDuration` instance can just be derived. It could also be written by hand

```instance AdditiveGroup TimeDuration where
zeroV = TimeDuration 0
TimeDuration δt₀ ^+^ TimeDuration δt₁ = TimeDuration \$ δt₀ + δt₁
```

One particularly nice thing about `AdditiveGroup`: it's a precursor to `VectorSpace` which gives you a multiplication that does make sense, namely

```instance VectorSpace TimeDuration where
type Scalar TimeDuration = Integer
factor *^ TimeDuration δt = TimeDuration \$ factor * δt
```

Can TimeDuration type be an instance of Semigroup and Monoid?, In an attempt to find a quick and easy way to add different time periods, it occurred to me that I could declare them instances of Semigroup and Monoid. Are the  Any datatype a which has an associative binary operation will be able to become a member of the Semigroup typeclass. An instance of Monoid a automatically satisfies the requirements of a Semigroup making Semigroup a strict superset of Monoid.

If we are writing an instance for a class with laws, the first sanity check should, in general, be whether the instance follows them. For `Semigroup`, there is the associativity law...

```(x <> y) <> z = x <> (y <> z)
```

... while `Monoid` adds the identity laws:

```mempty <> x = x
x <> mempty = x
```

Your instance follows the laws as long as only `S` values are involved (as it boils down to adding seconds). However, the identity laws are broken once the other constructors are brought into play, as in:

```mempty <> H 2 = S 7200
```

We might be tempted to argue that `H 2` and `S 7200` are morally the same, and the difference between them is merely a presentation issue (cf. how `show . read` is, strictly speaking, not `id` as it normalises formatting). The question, then, would become why are `H` and `M` necessary if they aren't meant to be used for any relevant distinctions (cf. the other answers).

Data.Semigroup, This makes a semigroup a superset of monoids. Therefore <> could be defined as + or * for instances of class Num a . Division Take a nonempty list of type a and apply the <> operation to all of them to get a single result. A semigroup generalizes a monoid in that there might not exist an identity element. It also (originally) generalized a group (a monoid with all inverses) to a type where every element did not have to have an inverse, thus the name semigroup.

This looks ok but why not just do this?

```newtype TimeDuration = Seconds (Sum Integer) deriving (Show, Eq, Monoid, Semigroup)
```

I think you need extensions to derive semigroup and monoid through the newtype, and you need to import `Sum` from `Data.Foldable`

You can have functions for the rest:

```seconds = Seconds
minutes = seconds . (*60)
hours = minutes . (*60)
```

Another thing you might want would be:

```data TimDuration = Duration { seconds :: Int, minutes :: Int, hours :: Integer }
```

And define a function to normalise this. But here’s a question to demonstrate that actually adding durations and times is difficult: is adding a minute the same as adding 60s? One would think so but what if say the time is 23:59:00 and the last minute has a leap second? In such a case if you add 60 seconds you get to 23:59:60. If you add a minute should you get 23:59:60 or 00:00:00 for the next day? In this case I think saying a minute is 60s is sensible. But how long is a day or a month? What happens if you add a day to 12:00 the day before the clocks change. Should you get 12:00 the next day or 13:00/11:00? And if you add a month to 29 January should you get 28 February or 1 March? And what about on leap years? Time is hard once things aren’t always seconds.

Monoid, In Haskell, the Monoid typeclass (not to be confused with Monad) is a class and indeed you can think of a Monoid instance declaration for a type m as Semigroup m => Monoid m where mempty :: m -- defining mappend is  In Haskell, the Monoid typeclass (not to be confused with Monad) is a class for types which have a single most natural operation for combining values, together with a value which doesn't do anything when you combine it with others (this is called the identity element).

purescript-datetime/Duration.purs at master · purescript/purescript , instance semigroupMilliseconds :: Semigroup Milliseconds where. append (​Milliseconds x) (Milliseconds y) = Milliseconds (x + y). instance monoidMilliseconds  Semigroup. If a type A can form a Semigroup it has an associative binary operation.

Lesson 17. Design by composition—Semigroups and Monoids, You can think of <> as an operator for combining instances of the same type. You can trivially implement Semigroup for Integer by defining <> as + . Listing 17.2.

Monoid, Integers, for example, are monoids under both a “sum” and a “product” operation. to have a Monoid instance, a type must also have a Semigroup instance. an identity value of some kind will be needed but the type cannot yet be known.