liveBook · Manning

Semigroup

As explained in Learn Haskell by Example

Semigroup is a Haskell type class for types with an associative binary combination operation.

A Semigroup is a Haskell type class for values that can be combined with an associative binary operation, written (<>). Associativity means parentheses may be regrouped: a <> (b <> c) == (a <> b) <> c. The compiler does not prove that an instance obeys this law, so the implementation must preserve it. section 7.3.1

Associativity does not make combination commutative. When compiling results, a <> b cannot generally become b <> a; only the grouping of operations may change. This makes Semigroup useful when a value has a meaningful append operation whose input order must remain intact. section 7.3.1

Appending CSV tables

A Csv value can use its existing appendCsv function as its Semigroup operation: instance Semigroup Csv where (<>) = appendCsv. Three tables can then be appended with either grouping while retaining their table order. The append operation combines headers and columns, filling uneven rows with NullValue where needed. section 7.3.1

Listing 7.10 Instances for Semigroup and Monoid for the Csv type
instance Semigroup Csv where
  (<>) = appendCsv  #1

instance Monoid Csv where
  mempty = Csv {csvHeader = Nothing, csvColumns = []}  #2

The Csv instances connect a domain-specific append function to the standard (<>) operator and define an empty Csv for Monoid. section 7.3.1

Semigroup design rules in practice:

  • Define (<>) as a binary operation for the type. section 7.3.1
  • Ensure regrouping does not change the result: a <> (b <> c) must equal (a <> b) <> c. section 7.3.1
  • Keep operand order meaningful unless the operation independently supports swapping operands. section 7.3.1
  • Avoid an ordinary Semigroup instance when several equally plausible associative operations exist and no canonical choice is available, as with Int addition versus multiplication. section 7.3.1

Monoid extends Semigroup with mempty, a neutral value: combining it on either side leaves a value unchanged. Monoid also provides mappend, equivalent by default to (<>), and mconcat for combining a list. Lists demonstrate both classes: (++) supplies combination, [] is empty, and strings can be appended the same way. section 7.3.1

Combining lists and text

[1,2,3] <> mempty <> [4,5,6] produces [1,2,3,4,5,6]. Likewise, mconcat ["Hello", " ", "World"] produces "Hello World". These examples show a familiar append operation reused through the common interface. section 7.3.1

Using Semigroup and Monoid instances lets code generalize behavior across types instead of naming one data representation. For CSV processing, (<>) can be selected as an optional append transformation alongside slicing and text search when building a command-line pipeline. section 7.5 section 8.4.1

How Learn Haskell by Example covers it

How deep it goes
Defines associativity, distinguishes it from operand swapping, and implements Semigroup for Csv without proving laws mechanically.
Examples
Demonstrates Csv table appending, list concatenation with mempty, and String combination with mconcat.
What it assumes
Starts from CSV appending and introduces Semigroup alongside records, Either, and custom type classes.
What you can do after
Apply it via (<>) to append Csv values while preserving operand order and allowing regrouped combinations.
How it connects
Connects Semigroup with Monoid, mempty, mconcat, lists, strings, CSV appending, and type classes.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Haskell by Example. The section links point to the parts of the book it draws on.