# Semi-Group#

A semi-group is a typeclass which can apply associative binary operation. So if a type is a semi-group, its binary operation `append` can be applied. It's associative so `SemiGroup[A].append(SemiGroup[A].append(a, b), c)` is equal to `SemiGroup[A].append(a, SemiGroup[A].append(b, c))`

e.g.)

import just.fp._
def foo[A](x: Int, y: Int, f: Int => A)(implicit S: SemiGroup[A]): A =
S.append(f(x), f(y))
// or with context bound
def foo[A: SemiGroup](x: Int, y: Int, f: Int => A): A =
SemiGroup[A].append(f(x), f(y))

If there is a typeclass instance of `SemiGroup` for a type `A`, `mappend` method or a convenient `|+|` infix operator can be used like this.

e.g.) There is already a SemiGroup typeclass instance for `Int` in `just-fp` so you can do

import just.fp.syntax._
1.mappend(2)
// res0: Int = 3
1 |+| 2
// res1: Int = 3

Typeclass instances for the following typeclasses are available in `just-fp`.

• `SemiGroup[List[A]]`
List(1, 2, 3) |+| List(4, 5, 6)
// res2: List[Int] = List(1, 2, 3, 4, 5, 6)
List(1, 2, 3).mappend(List(4, 5, 6))
// res3: List[Int] = List(1, 2, 3, 4, 5, 6)
• `SemiGroup[Vector[A]]`
Vector(1, 2, 3) |+| Vector(4, 5, 6)
// res4: Vector[Int] = Vector(1, 2, 3, 4, 5, 6)
Vector(1, 2, 3).mappend(Vector(4, 5, 6))
// res5: Vector[Int] = Vector(1, 2, 3, 4, 5, 6)
• `SemiGroup[String]`
"abc" |+| "def"
// res6: String = "abcdef"
"abc".mappend("def")
// res7: String = "abcdef"
• `SemiGroup[Byte]`
1.toByte |+| 2.toByte
// res8: Byte = 3
1.toByte.mappend(2.toByte)
// res9: Byte = 3
• `SemiGroup[Short]`
1.toShort |+| 2.toShort
// res10: Short = 3
1.toShort.mappend(2.toShort)
// res11: Short = 3
• `SemiGroup[Char]`
'A' |+| '1'
// res12: Char = 'r'
'A'.mappend('1')
// res13: Char = 'r'
• `SemiGroup[Int]`
1 |+| 2
// res14: Int = 3
1.mappend(2)
// res15: Int = 3
• `SemiGroup[Long]`
1L |+| 2L
// res16: Long = 3L
1L.mappend(2L)
// res17: Long = 3L
• `SemiGroup[BigInt]`
BigInt(1) |+| BigInt(2)
// res18: BigInt = 3
BigInt(1).mappend(BigInt(2))
// res19: BigInt = 3
• `SemiGroup[BigDecimal]`
BigDecimal(1) |+| BigDecimal(2)
// res20: BigDecimal = 3
BigDecimal(1).mappend(BigDecimal(2))
// res21: BigDecimal = 3
• `SemiGroup[Option[A]]` if there is a typeclass instance of `SemiGroup[A]`.
1.some |+| 2.some
// res22: Option[Int] = Some(3)
1.some.mappend(2.some)
// res23: Option[Int] = Some(3)

NOTE: There might be an associativity issue with `BigDecimal` if it's created with other `MathContext` than `MathContext.UNLIMITED` and the number is big enough in Scala 2.13.