Semi-Group

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.

More about the issue, please read this blog.