I was ruminating on Semigroups this morning.

In Haskell, a Semigroup is a combination of a type and a function taking two of that type and returning a new one, where the function is associative.

Let’s see if some different things are semigroups: * Int and +: (x + y) + z == x + (y + z) :heavy_check_mark: * Int and *: (x * y) * z == x * (y * z) :heavy_check_mark: * Int and /: (x / y) / z != x / (y / z) :heavy_multiplication_x: * String and ++ (concatenation): (x ++ y) ++ z == x ++ (y ++ z) :heavy_check_mark: * Maybe String and concatenation whenever there is a value:(Just "ab" <> Nothing) <> Just "cd" == Just "ab" <> Just "cd" == Just "abcd" Just "ab" <> (Nothing <> Just "cd") == Just "ab" <> Just "cd" == Just "abcd" :heavy_check_mark:

In Haskell <> generalises all of these operations.

Yesterday @Yura showed us some code like long "verbose" <> short 'v' <> help "Enable verbose mode" Even if you don’t know what type it’s dealing with, you still know it’s joining them all together, and any part of it can be refactored out. So without any anxiety at all, we can change it to

let verboseOptions = long "verbose" <> short 'v'
in verboseOptions <> help "Enable verbose mode"

Compare with, for example, joinOptionModifiers (long "verbose") (joinOptionModifiers (short 'v') (help "Enable verbose mode")) where you’d have to look up the definition of joinOptionModifiers to know what its return type is, or if it can be refactored in any way.

Powered by Hugo & Kiss.