## Tuesday, July 4, 2017

### Functional Foibles

Functional languages are supposed to protect you from nasties like NullPointerException etc but there are some gotchas.

a[NoSuchElementException] should be thrownBy {
}

\$ ghci
GHCi, version 7.10.3: http://www.haskell.org/ghc/  :? for help

But this little annoyance occurred in a Spark job (here illustrated with ScalaTest):

an[UnsupportedOperationException] should be thrownBy {
List.empty[Int].max
}

A neat mitigation can be found here and looks like this:

List.empty[Int].reduceOption(Math.max) shouldBe None

An interesting point was made here on how things should be:
I would suggest that max is not an option. If you have a type (empty[T]), then this fold (I mean max) should return the neutral element regarding max(x,y), that is, the minimal element of the (partial) order of T, if one exists; if it does not, then it makes sense to throw an exception.
Same as with other monoidal operations, e.g. empty.sum is a zero, not an exception.
This would be the right mathematical answer.
As a reminder, partial ordering exhibits anti-symmetry, transitivity and reflexivity, that is x ≤ x (contrast this with total ordering which exhibits anti-symmetry, transitivity and totality, that is x ≤ y or y ≤ x).

So, what's being said here is that the minimal element for, say, a Double is Double.MinValue. This is indeed transitive (obviously), reflexive (clearly MinValue  MinValue) and anti-symmetric (if MinValue  x and  MinValue then the only conclusion is x = MinValue).

Compare this to Double.NaN which is not reflexive and therefore a partial ordering does not exist.

So, to be mathematically correct, List.empty[Int].max should return Double.MinValue.

"Head is a different story; here we have a semigroup, not a monoid. There's no neutral element."

And so it is:

List.empty[Int].sum shouldBe 0