Which Programming Languages Are Functional?
blog.jenkster.com
blog.jenkster.com
Yet most people forget it about when talking about "functional", and end up comparing Python to Haskell basically. Maybe with F# thrown in there for good measure.
Erlang has solid closure support, tail call elimination, immutable data structures and variables, encourages using recursion instead of for loops, in practice folds/maps are common constructs instead of an oddity etc (like say in Python).
It even has an optional success typing system:
http://learnyousomeerlang.com/dialyzer
EDIT: Elixir is using Erlang's VM as well and almost everything about language features above apply to it. If you don't want to give Erlang a try, check out Elixir. It also has one of the friendliest communities for new-comers.
Someone down the line probably mentioned to them "Hey, btw, did you know you have a functional language?" And they probably shrugged and said "Oh, cool!"
I would guess Joe, Robert or Mike never went about reading papers on type theory, thinking about meta-circular evaluators, or y combinators etc and said "We need that, let's implement it!". Instead, they started with stuff like "let's minimize state" so made state explicitly passed in. "Let's minimize mutable state", so make data immutable. So then need recursion instead of for loops, so let's think about tail call elimination. They played with Prolog so language inherited the base Prolog syntax which has a functional taste to it, that helped as well.
The same thing kind of happened with the actor paradigm. They never started with a goal of implemented an actor / message passing programming paradigm. It just fell out of fault isolation property. Someone later told them "Oh btw, did you know you have implemented the actor paradigm?" and they probably shrugged and said "Oh, cool!" and went back to doing whatever they were doing.
That was actually how he described tail call elimination in his LFE talk: "of course you have TCE/O, why the hell wouldn't you?"
Which was a refreshing perspective to me, considering how many programmers still seem to have been heavily indoctrinated to the idea that recursion is automatically bad.
Erland on the other hand, is targeted on soft-real-time distributed systems. How was the quote? "Every soft-realtime highly availabe distributed system contains informally specified, incomplete and bug ridden implementation of erlang." Or something like that.
This property makes Erlang programs incredibly easy to reason about and test.
To me, "functional programming" taken back to origins in Lisp and the lambda calculus is a style of programming that focuses on the composition of functions.
The "purity" element is merely the consequence of this focus: in order to be composable, our functions largely need to be free of side effects, and take and return values as mathematical functions do.
I think the emphasis on function composition also makes for a better, more believable sales pitch, once you take into account first-class functions as values and the kinds of abstractions and patterns they allow. I have a version of this pitch which goes like this:
Imagine a function that, given the right inputs, could produce any output in the known universe. To which you might rightly answer "that's pure nonsense". The sheer volume of internal logic would naturally be more complicated than everything within that universe.
But if that function can itself receive other functions as inputs, then the potential outputs expand almost infinitely.
And indeed, this is why the lambda calculus itself has proved Turing-complete: simply by composing functions within functions in this way, you can literally recreate the whole of computing and mathematics.
In practice though, people have their limits, and the day to day operation of a computer does require occasionally breaking the perfect mathematical puzzle for the sake of getting work done, and the vast majority of languages in existence allow for exactly that. A definition that doesn't allow for them might well be "true" in the "pure" sense of the word, but it's not very useful for people other than mathematicians.
And hell, even the Turing-machine uses mutable state.
Then because those are pretty reasonable language features all the languages that had been written in the late 80s-mid 90s and became popular around 2000 had those features.
So then for a while 'functional' was just sort of way of saying 'not java'.
Now 'functional' seems to mean strong algebraic typing for some reason.
The functional programming paradigm models computation as a relation between sets, and is thus inherently declarative. However, in practice, we often think of functions as imperative, ie you put in an input value and get out an output value, same as with a procedure. From this point of view, the characteristic property of a function is that it has no side-effects. Because of ambiguity of the terms, we call such a function pure, and a language which only has pure functions would be a purely functional language.
However, not all functional languages are pure: A functional language is a language with syntax and semantics which allows the programmer to use the functional paradigm efficiently. Some of the concepts which make using the paradigm feasible include - among others - lambda expressions with lexical closure, higher-order functions, variant types and pattern matching, lazy evaluation, type-inference (in case of statically-typed languages).
This is by no means an authorative list, and a language can very well be functional without providing all or even most of them, but if a language does - ie makes them usable without having to jump through major hoops - their presence is a strong indicator that the language should be considered functional.
[1] https://downloads.haskell.org/~ghc/latest/docs/html/librarie...
[2] http://hackage.haskell.org/package/vector-0.11.0.0/docs/Data...
[3] https://downloads.haskell.org/~ghc/latest/docs/html/librarie...
It's pretty cool; you can use ST to have mutable variables and arrays and such, but the mutable values aren't allowed to escape the ST "context". So you're still guaranteed immutability outside of the ST monad, because the type system locks all mutable values inside the monad.
This is mostly only used in very-high-performance libraries that use algorithms based on array access.
Don't ever be a 'programming language 'x' guy or girl'. Be yourself, know some tools and skills and be prepared to switch those out for whatever works best in that particular application. If you limit yourself to a certain programming language, no matter how great it seems to be today you've built in your own obsolescence.
Better to be a guy or a girl with x years of Haskell experience and a whole bunch of other stuff besides.
The author seems to believe that no side effects is the key property of a functional language. But for me most problems I deal with (user interface, various business domains, integration with other systems over network etc.) are filled with state and procedures. Sure you can deal with that in a purely functional way but to me it is a bit like doing object-orientated programming in C with macros and a lot of conventions. Why not simply use a programming language with suitable primitives? In particular now that multiparadigm languages are the most widely used in our industry.
It is easier to reason about functional programs because they maintain certain properties. These could be types, an absence of side effect, etc. This is the point of the entire article.
You get none of those benefits if your "multi paradigm" language allows you to break those guarantees.
For a multi paradigm language to derive benefits from functional programming, it should allow developers to explicitly write guarantees that can be enforced at compile time. This is a promising direction but, to my knowledge, it's not available in any of the languages you mentioned.
If you had a multi-paradigm language, you'd need not only just some way to break the rules easily and have that bubble up, you'd also want this rule-breaking behavior to be exposed up the chain from any libraries. You'd also have to enforce the benefits of immutability and such through social pressure in order for users to see large parts of the benefits of side-effect isolation.
A lot of the choices FP languages make that are less about side-effects (like strict typing systems) are also often an all-or-none proposition. Optional typing systems have very limited benefits if libraries aren't well-typed. The static analyzers can only do so much.
That's what I used to think, and in fact I still think like that somewhat, but do note it's explicitly mentioned as a red herring in John Hughes' well-known and often quoted paper "Why Functional Programming Matters".
From the paper:
> Such a catalogue of “advantages” [things that FP lacks or constraints] is all very well, but one must not be surprised if outsiders don’t take it too seriously. It says a lot about what functional programming isn’t (it has no assignment, no side effects, no flow of control) but not much about what it is. The functional programmer sounds rather like a medieval monk, denying himself the pleasures of life in the hope that it will make him virtuous. To those more interested in material benefits, these “advantages” are totally unconvincing.
> [...]
> Functional programmers argue that there are great material benefits — that a functional programmer is an order of magnitude more productive than his or her conventional counterpart, because functional programs are an order of magnitude shorter. Yet why should this be? The only faintly plausible reason one can suggest on the basis of these “advantages” is that conventional programs consist of 90% assignment statements, and in functional programs these can be omitted! This is plainly ridiculous. If omitting assignment statements brought such enormous benefits then Fortran programmers would have been doing it for twenty years. It is a logical impossibility to make a language more powerful by omitting features, no matter how bad they may be.
He then goes on to argue that the real benefit of FP languages is that they excel at modularity, a widely agreed upon trait of good software, and that they have an excellent mechanism for "gluing" stuff together, i.e. lazy evaluation.
(I've since read that some FP devs disagree about the importance Hughes placed on laziness).
Of course it's about modularity, but how do you get modularity? How do you safely abstract the internals of libraries? Types and lack of side effects!
It's also about correctness. Most of the time spent writing any complex bit of software is generally spent finding out what's wrong with it.
Even philosophically this position is weak. It's self-evident to me you can make something more powerful/better by removing things. You can make something better by removing risks. You can make an UI saner by removing the possibility of invalid interactions. You can make art better by removing superfluous details.
I still think that types and control of side effects is essential to (good) FP.
- You can make limbs more useful by removing degrees of freedom, simplifying the control task.[2]
Static languages such as Java and C# are not OK though. For one they lack features that are essential for statically typed languages. For example higher kinded types is an essential feature for FP. Without that you can't build libraries of reusable FP stuff. Comparing it with Scala for example you can't build Scalaz or the newer Cats or Shapeless [1].
The other problem is that FP programming languages come with FP libraries. You can't underestimate the importance of having good implementations for persistent collections be the default.
On having "no side effects", that's not what FP is about. After all, without side-effects you couldn't get any output out of a program. FP is about encoding those side-effects in types and abstractions you can reason about, or in other words it's about controlling side-effects. Haskell developers are fond of their IO monads. FRP is another way of doing that, being particularly good at dealing with user interfaces. And for example FRP-related libraries that were born by playing to the strengths of the mainstream languages we are dealing with are Facebook's React and Microsoft's Rx.
BTW, this is one of the best books on functional programming available today: http://www.manning.com/bjarnason/
[1] https://github.com/scalaz/scalaz, https://github.com/non/cats, https://github.com/milessabin/shapeless
My personal definition of 'functional' is based on this lack of side-effects (or, more abstractly, on modelling computation as a declaration of relations between sets, which is what mathematical functions are), but it gets fuzzy once you leave the realm of purely functional languages.
If you prefer another definition for pragmatic reasons, I'm fine with it, it's just not my choice.
And languages I listed (JavaScript, C#, Swift and Java) have all stolen large chunks of ideas pioneered by functional programming and put it into their latest release.
Procedures can be modeled as functions, state can be passed around, user interface hotness currently is also trending to functional / immutable (Elm, React).
> bit like doing object-orientated programming in C with macros and a lot of conventions.
If you are forced to use C and macros yeah it is no fun.
But if you have tail call optimizations, a good type system (even optional one like Erlang does), immutable data structure support, monitoring and tools (Erlang VM), you can build large systems that handle lots of mutable state in a sane way.
Doesn't matter what language or OO heavy framework (worked on Python, C++, C, C#, Java over the years) if there is lots of mutable state stored in class instances, it makes it very hard to jump in and understand a new large code base. While say something written in Erlang the state is explicitly passed around, it is minimized, and looking at a piece of code it easy to understand what happens vs say looking at somethingSomethingManagerInstance with 100 methods and 100 private data attributes, and understand when something breaks how it go to that broken state.
That's just my observation based on systems I worked over the years.
The sole specifier 'pure' is meaningless without context...
> public String getName() { return this.name; }
> How would we purify this call? Well, this is the hidden input, so all we have to do is lift it up to an argument:
> public String getName(Person this) { return this.name; }
> Now getName is a pure function.
Isn't that just syntactic sugar? I would say that a real functional programming language enforces that functions cannot have side effects, not just that you have the ability to write such functions.
The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures." Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress. On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.
Source http://c2.com/cgi/wiki?ClosuresAndObjectsAreEquivalent
A lot of the argument for "composition over inheritance", SOLID etc. is separating the pieces of state that specific object methods depend on. I don't think the Python approach helps that much in practice (since method calls look exactly the same), but it does make it much clearer where anything referenced in a method body has to be coming from.
They're implicit mutable state. Whether you think that has anything to do with functional programming is another matter, I suppose.
Further, purity is about expectations, not scope. Expecting something to be pure means I can reliably call it with the same arguments and always get the same result, with the additional expectation that it will change nothing about the world. A function that accepts no arguments can be pure but must always return the same thing. If the person's name is indeed immutable, then person.getName(), provided it performs no side effects, is perfectly pure.
In concept, other than brevity, invoking a constructor on an immutable object is not much different than the function returned by a higher order function such as this:
(defn name-getter [{name :name}] (fn [] name)) (def get-name (name-getter {:name "John"})) (get-name)
person.getName() is the same as getName(person). In the former it's an implicit parameter, in the latter it's explicit. Or, looking at it differently, one is a syntax for functional calls that prepends the first argument as a target, and one is a syntax that accepts the target as the first argument.
With Java 8 method references, you can see this a bit more clearly. You could, for instance, do this to get a function without the implicit this:
Function<Person, String> getName = Person::getName; getName.apply(new Person());
def getName():
. . this.setName('foo')
. . return this.name
There's nothing in principle preventing you from doing that in the "functional" approach but if your data is immutable then you can't do it.
def getName(person):
person.setName('foo')
return person.name
The problem, from a functional viewpoint, isn't the implicit argument, it is the fact that you can write setName.Except PHP. PHP still sucks.
The logical extreme would otherwise be to switch to a new tool whenever one comes out that is objectively better at a given task and retrain every team member that was previously using the old tool and rewrite the code that relies on the old tool to use the new tool.
This balance is called pragmatism and it's more important in the real world than the objective quality of tools you don't already have in your toolbelt.
OCaml may be a little obscure in the mainstream programming community, but there are a ton of folks using F# out there.
Don't have time to do the full internet report for you, but if you're interested, the way to tell is simply google various programming problems with F# instead of C#.
Five years ago you could mostly find C# code and convert in your head. Now about 80% of the time you can find what you're looking for in F#. That's a ton of people.
Signals are way easier to understand (for me personally) than monads. I just wish it had better Javascript interop. Making ports for everything to talk to an existing API (like three.js) is a deal breaker.
as my guide. I think it just comes down to "I don't have time to rewrite bindings for an entire API right now" because ports require you to really understand what's going on. There's no shotgun method of converting an entire API.
Another reason I gave up is that Purescript does have three.js bindings.
Yeah this means C function pointers allow some FP. Except they're clunky and have a hard time bundling info with them (no closures). This makes HOFs sort of a pain.
Controlling state, or at least immutability, is just a generally good idea. Even in rather non-FP code I wish I had easy immutability.
With that definition, functional programming is a style, not a class of languages. An assembly routine that computes a cosine is a functional program. I typically write C/C++ code in a functional style, constructing and returning new data structures rather than modifying arguments in place, because it's so much easier to test, use in parallel code, and reuse later.
So I don't think that strong typing, higher kinds, higher order functions, algebraic types, pattern matching, anonymous closures, polymorphism, or garbage collection, e.g., are necessary to functional programming (although they're all wonderful and Haskell seems to have collected just the right mix of features together into a language that I love using whenever I can). It's about whether or not your components have interfaces that are like mathematical functions.
What?!
In any case, i've suggested a correction here: http://blog.jenkster.com/2015/12/which-programming-languages...
perl -e 'for (1,2,3,4) { for (5,6) { print " $_\n" } print "$_\n" }'At the very least, I suspect honesty will compel you to admit that either A: that took you longer than you expected or B: you left out a lot of corner cases, especially when modifying $_ does or does not change the thing it does or does not reference, and how it interacts with local, and, and, and....
Yes, it took a little longer. No, it didn't took that much longer to leave out plainly invalid and misleading description. No, I didn't need to put corner cases there, exactly the same way as you wouldn't specify corner cases for Yacc to describe what it does.
What irked me is that's just about all the author's got to say about Perl in the article. Other languages inherited this "feature" (Ruby anyone?) or equivalents, but no mention of that. Why even mention Perl if he's got nothing (solid) to say about it?
I also did not take longer than expected, nor did i leave out any corner cases that affect day-to-day work and am not aware of many of them existing in the first palce.
But sometimes you end up using it to make code more reliable, as in:
do_thing($_) for @things;
Where $_ is passed in as an argument, as opposed to: do_thing for @things;
Where $_ is (due to its global nature) set by `for`, and read in sub do_thing { ... }Most people don't. The only one that is used a lot is @_. :)
As for debugging old code, that's why i pointed out perlvar. It's never far and it's always easy to look up what a specific var does.
But Lisp is not a functional language! It's based on the concept of CONS which is mutable and allows for shared structure. Lisp is #1 language that everyone thinks is functional when it's actually not. I'm surprised this article out of all made this mistake.
On one hand, the idiomatic emphasis on tail calls (supported by tail call optimization in the language) makes it easy to avoid stateful for and while loops.
On the other hand, most nontrivial code has plenty of `set!`s.
In Scheme, one can build functional systems on top of imperative building blocks. For example, memoization can be implemented as a higher-order procedure that uses a mutable hash table as the cache. A memoized function is still pure, despite the use of local state, because it retains the crucial property of referential transparency.
Anyway, I guess my point is that the use of 'set!' or 'hash-table-set!' or whatever else doesn't mean that a program is no longer using the functional paradigm. To quote from a Clojure web page[0], "if a pure function mutates some local data in order to produce an immutable return value, is that ok?"
"If you write Java code that has no side-effects, that doesn't read or change the local object's state, you'll be called a Bad Programmer."
No you won't.
"Java thinks that localised side-effects are cornerstone of good code"
Java doesn't think anything. It's a tool.
"Unfortunately, in practice Java doesn't just try to encapsulate side-effects; it mandates them"
No, it doesn't.
I will say I've worked in Java shops and seen the language used in this way. I've also worked in Java shops and seen people who have read and internalized the messages in Effective Java, especially with regard to handling state, and the codebase looked nothing like what is described in this article. I recommend the author take some time to read that book and keep reminding himself that Java is a generalized tool that can be used in many ways.