Dynamic functional languages: Clojure, Common Lisp, Racket and Scheme. They have few types often only known at run time.
Statically typed functional languages: F#, ML, Haskell, Idris and Scala. They have advanced types that are known at compile time.
Functional programming languages have similarities but are very different from one another. Some are quite hard to learn. What should you pick?
SlogansHere are two extreme positions in functional programming reduced to slogans:
Lisp: Everything is DataLisp has a great story: Everything is data.
Lisp is homoiconic. There is one datatype: The S-expression in Lisp or an EDN in Clojure. This encodes:
Haskell: Everything is a ComputationComputation sounds like an equally strong unifying foundation. This is a strong counter argument to Lisp.
Haskell turns the world into mathematics by giving strong guarantees and the ability to reason about programs. It is fast, elegant and remarkably safe.
Most of the world is messy so programming in Haskell is both an art and a science.
A Type System is a Must For Production CodeIn my experience:
A complex production server application demands a static type system for stability
The type system is doing at least half of my work when I work alone and prevents total anarchy when working in teams.
History of Static and Dynamic Type SystemLike many other programmers, I have gone back and forth between preferring static and dynamic languages several times.
C++ and JavaI started using and loving the sophisticated statically typed object oriented languages: C++ and Java.
Why would anybody want to program in Basic?
Perl, Python and RubyAt some point I had to make a small script for text processing. I realized that dynamically typed languages Perl, Python and Ruby are much simpler and faster to work with.
They borrow a lot of ideas form functional languages and saves you a lot of boiler plate. Programming became fun again.
I never wanted to go back.
F#, Scala and HaskellThen came the raise of F#, Scala and Haskell.
I thought that you got the best of both worlds:
- There are few visible types due to type inference
- They look like dynamic language
- Still you get strong safety from the invisible type system
- They are fast
Living with Static TypesFor the last 4 years I have been happy programming in Scala. It really improved my productivity.
I mainly deal with stable data types. Each data structure get immutable case class and they flow beautifully and it even works well in a concurrent system.
I am a little concerned about the amount of black magic going on at the type level in Scala and Haskell.
Web, Scripting and Data ExplorationSome fields continue to be dominated by dynamic languages:
- Data exploration
- Data science
Dynamic languages have an edge for small systems.
Problems Using Scala for NLP
Idiomatic Scala has been great for NLP.
I had to extract all the hidden and visible information on a html page and had to parse the DOM tree for everything: elements, attributes, code and json data.
The DOM tree is similar to an S-expression.
The best idiomatic Scala representation I could find was Play JSON. The DOM tree and Play JSON are not that similar and processing json in dynamic languages is more natural than in strongly typed languages.
Dynamic languages have an edge for some complex systems.
Lisp RevisitedI used Lisp in school. It was the cool AI language and my first functional language. I loved it, it blew my mind but I had a very shallow understanding.
Impressions from revisiting Lisp after using statically typed functional languages:
- Lisp is small and elegant
- Easy learning curve
- Great at traversing dynamic data
- Well suited for exploration
- A lot of the principles of statically typed functional programming translate directly
- I still think in Scala like types making my Clojure code better organized
- Macros feel natural unlike in C++ and Scala
- Lisp is really fluid combining in so many crazy ways
- You lose a lot of safety
Going from Haskell to Clojure left me with the feeling I had when moving from C++ to Python. You get a lot of value for less effort.
Raise of the Gradual Type SystemsThere has been slow movement towards gradual types. Here are a few place where they have popped up:
- C# 4 has dynamic type
- Clojure with Typed Clojure
- F# dynamic type providers that loads strong types at run time
- Hack Facebook's optional typed PHP
- Python with mypy
- Racket with Typed Racket
- Scala.js has js.Dynamic
Ambrose Bonnaire-Sergeant on gradual typing in Clojure
The type systems in Typed Clojure and Typed Racket are pretty different than in Scala and Haskell. Generally weaker, but Typed Clojure and Typed Racket have union types that are only now investigated in Scala's experimental new type system Dotty.
These advances in gradual types make it possible to harden Lisp code to improve stability.
Data or CalculationI was puzzled by the Lisp and Haskell slogans:
- Everything is data
- Everything is a calculation
I could not easily dismiss either. For now I have accepted that we are stuck with both.
For a long time I suffered from the misunderstanding that F#, Scala and Haskell are like dynamic languages, with the addition of speed and safety. But they are fundamentally different.