Scalaz has so many abstractions and higher kinds that model lot of algebraic structures, monads, hight level types to generalize common structures and offers lot of tools that work with those abstractions. In this article I wanted to cover the very basics. Ones we see every day in standard scala library. What the anomalies of basic types are in standard scala library, what are the comment things between them that can be made generic, how to use scalaz with standard classes defined in scala library.
Semigroup brings append operation and it should be associative. We see in standard library append operation is everywhere, numeric types, strings, lists, etc. All have a way to add one instance to the other, for number types it would be the + function and for lists ++. Scalaz has syntactic sugar, having |+|, mappend, ⊹ to all be same as append. I particularly like ⊹. We say if a and b are from same semigroup then we can append a to by by doing a ⊹ b. Cleans things up little bit for sure, we don’t say if a and b are strings it’s +, if a and b are lists it’s ++.
Next comes Monoid. Monoid is a Semigroup and it also has zero element. There is left and right identity with zero element, meaning:
Again scalaz defines few synonyms for zero, mzero and ∅. In scala library we already see monoids. For integer a, a + 0 = 0 + a, for string a a + “” = “” + a, for list a, a ++ Nil = Nil ++ a, etc.
So how do we make standards classes to be scalaz semigroups or monoids since those already have associative append and zero element. Having that ability we can say just write ∅ instead or 0, “”, Nil, etc. And ⊹ instead of +, ++, etc. Scalaz defines Semigroup[F] and Monoid[F] as traits, if we say F type is a monoid we need to extend Monoid[F] and provide implementation for append and zero methods, associative and identity lows should also be satisfied. Luckily for us scalaz defines instances that provide implementation for unit, boolean, byte, char, int, long, float, double, string, option, list, future and many more under scalaz.std package and those are implicit objects so bringing those in scope will make a particular type to act as monoid. Just be careful what instance to bring in scope, for example integer is a monoid over 0 and + operation and also over 1 and * operation, boolean is a monoid for conjunction and disjunction.
Equal is another one that we say most often in scala library but equal on it’s own has lot for variations, starting from java’s == and equal gotchas, scala’s == not being type safe and so many libraries in scala word defining ===. And it’s fair, to be completely honest and it all depends how we define what a equals to b means. Before we delve deep to see what scalaz has to say about equal, let’s see how scala’s == operator isn’t type safe:
This actually compiles but will return false, looks like common bug one can make to me. So there is basically equal function defined which is more than happy to take two arguments of different types. So solution seems to be to have some version of equal method that will force that both parameters are of the same type and it will make it type safe.
scalaz defines Equal[F] trait, which has def equal(f1: F, f2: F): Boolean, equal method. Both parameters are of type F. Also equal has to be
- commutative (if f1 equals to f2 then f2 should be equal to f1)
- reflexive (f is equal to itself)
- transitive (if f1 equals f2 and f2 equals to f3 then f1 equals to f3)
Defining equal method well automatically get not equal (it’s same as !equal), scalaz defines ===, ≟ as synonyms for equal, and =/= and ≠ for not equal.
Order[F] extends Equal[F] and brings in order function:
Where Ordering is a sealed abstract class with Ordering.LT, Ordering.GT and Ordering.EQ implementations. Providing a definition for order we get following for free from Order trait and OrderOps class:
- <, lt and lessThan
- <=, lte and lessThanOrEqual
- >, gt and greaterThan
- >=, gte and greaterThanOrEqual
- cmp, ?|? and order
Another one that’s useful is Enum[F] which extends Order[F] and defines succ, pred to get successor and predecessor of value f of type F. succn, predn to get nth successor and predecessor of value f of type F. min and max functions for minimum and maximum values. We also get following synonyms and derived functions:
- -+- and succn
- — and predn
- |=> and fromTo
- |-> and fromToL
- |==> and fromStepTo
- |–> and fromStepToL
Next abstraction I want to cover from scalaz is Show[F]. Show[F] defines shows method, which having f instance of F will return it’s string representation. Scalaz defines print and println derived functions to ShowOps class which are implemented as:
Implicit instances for integer and string
Let’s have a look to see how implicit objects for integer and string I mentioned before are implemented in scalaz. As we can see integer is a monoid, show and enum, where string is monoid, show, equal and order. String isn’t an enum because successor and predecessor functions don’t make much sense for strings. Also those implementations give good idea about how to implement those traits for our own classes.