Wednesday 12 October 2016

Day 1: Functional Programming

Brian May lookalike, Russel Winder, used to be a theoretical physicist working in QCD before he took up functional programming. He is a man who is very certain of his opinions. He began the workshop by declaring that Java is dead! He then qualified that by saying that Java is dead in the same way that Cobol is dead - it will take a thousand years before it finally disappears. Also, Scala is on the way out - apparently.

First, we compared the classic imperative paradigm, in which we dictate what the computer must do:
  • explicit iteration (loops)
  • mutable variables (watch for surprises: should use "final")
Contrast with the declarative paradigm, in which we let the runtime environment decide how to achieve the desired result:
  • implicit iteration (let the JVM work out the best way to iterate depending on the hardware)
  • immutable variables (harder to get it wrong).
We then moved on to the Hello World example - calculating factorials. If he were to condescend to use Java, he insisted on it being Java 9. At a push, he would go to Java 8 but not a minor revision lower. For the example, we used Frege (also know as, Haskall for the JVM). We started with a TDD approach, at which point he mentioned that the latest wisdom is to move from:
  • Example-based testing: x -> !; check for (0, 1), (1, 1), (7, x5040) etc.
to
  • Property-based testing: n=0, f(n)=1; n>0, f(n)=n*f(n-1) (Test uses recursion...). Examples are generated randomly by the JVM.
We then moved on to the fizzbuzz problem. We are looking for 1 ,2, fizz, 4, buzz, fizz, 7, 8, fizz, 10, 11, fizz, 13, 14, fizzbuzz,... and so on. Our first attempt was:

fizzbuzz = iterator 100 []
  where iterator 0 a = reverse a
        iterator i a = iterator(i-1)(a ++ [fb i]
  where fb x = if x mod 15 == 0 then "fizzbuzz"
               else if x mod 5 == 0 then "buzz"
               else if x mod 3 == 0 then "fizz"
               else show x

This works, but the fb function is basically Fortran and we are explicitly iterating. In a functional paradigm, this becomes:

choose x = if x mod 15 == 0 then "fizzbuzz"
           else if x mod 5 == 0 then "buzz"
           else if x mod 3 == 0 then "fizz"
           else show x
fizzbuzz = map choose [1..100]
main = println fizzbuzz

So the map function applies the choose algorithm to each element of the list (implicit iteration) However, we still have a Fortrany block in the choose method. Luckily, we have more functions:

fizzes = cycle ["", "", "fizz"]
buzzes = cycle ["", "", "", "", "buzz"]
fizzbuzzes = zipWith (++) fizzes buzzes
result = zipWith chooser fizzbuzzes [1..]
  where chooser s n = if s != "" then s
                      else show n
main = println (take 100 result)

The cycle function returns an infinite list that cycles among the elements. zipWith interleaves two lists into a list of 2-tuples. chooser takes each 2-tuple off the list and tests its elements.
  • fizzes gives us "", "", fizz, "", "", fizz, etc.
  • buzzes gives "", "", "", "", buzz, "", etc.
  • fizzbuzzes interleaves the fizzes and buzzes ("", ""), ("",""), (fizz, ""), ("",""), ("",buzz), etc.
  • result interleaves numbers with the fizzbuzzes, but uses the chooser function to decide what to select - if there's a word print it, else print the number.
The logical structure is reduced to a simple if..else, the iteration disappears and the infinite lists are never instantiated; we only use, at run-time, as much of the list as we need.

The next part of the workshop consisted of translating the solution above into Java. The key feature used was the Stream Interface, which allows us to connect to the fizzes and buzzes lists without instantiating them. The StreamUtils package provided the zipWith function and iteration was avoided by implementing the map-reduce pattern.

Finally, we embarked on yet another functional language, Kotlin. Actually, it turns out this one has procedural and object-oriented elements to it. Chatting to Brian later, I mentioned that I was beginning to suffer from language-fatigue, as yet another new language becomes the flavour of the month. What was wrong with Scala, I asked. His reply was that Scala was the first-pass at an enterprise-grade functional language. He thought it a solid effort, but feared that it had some basic design flaws that will limit it eventually. In his opinion, Kotlin is the real deal...

No comments:

Post a Comment