
A Year of Functional Programming - Garbage
http://japgolly.blogspot.com.au/2014/06/a-year-of-functional-programming.html
======
jacquesm
" Recently I looked at some code I wrote 8 months ago and was shocked! I
looked at one file written in “good OO-style”, lots of inheritance and code
reuse, and just thought “this is just a monoid and a bunch of crap because I
didn't realise this is a monoid” so I rewrote the entire thing to about a
third of the code size and ended up with double the flexibility. Shortly after
I saw another file and this time thought “these are all just endofunctors,”
and lo and behold, rewrote it to about a third of the code size and the final
product being both easier to use and more powerful."

That would be so much more useful if it came with the examples.

~~~
bkirwi
If you're interested in examples of useful monoids and similar structures, you
may want to have a look at the Algebird[0] project or the recent work on
CRDTs[1]. The code savings in these projects comes from being able to write
the complex distributed aggregation / conflict resolution / etc. code just
once, and reuse it with a menagerie of useful implementations.

Personally, I like structuring things using these tools when I can get away
with it. They're simple and broadly applicable abstractions, and mean I can
reuse both my intuitions and my code in wildly diverse situations.

[0] [https://github.com/twitter/algebird](https://github.com/twitter/algebird)
[1] [http://highscalability.com/blog/2010/12/23/paper-crdts-
consi...](http://highscalability.com/blog/2010/12/23/paper-crdts-consistency-
without-concurrency-control.html)

~~~
seanmcdirmid
What we want is a comparison: what was the OO code, and what did the
functional code turn out to be? That way, we can judge for ourselves.

Typically, these examples take low-end crappy OO code and convert it to high-
end elegant FP code. But this doesn't really convince anyone.

~~~
samstokes
I don't know the OP's examples, but I think he is saying something subtly
different: that he took (his own) low-end crappy OO code and converted it to
high-end elegant _OO_ code, using the insight gained from _how_ he would have
written it as FP.

~~~
seanmcdirmid
I didn't get that from the article, but they aren't explicit about it.

~~~
jacquesm
I got that too, and that's exactly why I would like to see the code before and
after. That's far more interesting than the rest of the article in my opinion.

------
mark_l_watson
Nice article!

I have been using Clojure for years, initially because a repetitive customer
mandated its use, later for my own projects because it reduced my development
time and is fun to code in. I tried Scala (really liked Martin Odersky's
Coursera class!) but it did not stick.

That said, Haskell has started to win my mind share. At least for my own
projects I have been mostly using Haskell this year, with some bits of Ruby
for quick text processing and munging. When my Haskell abilities improve I
would like to start using it for small text processing utilities also.

Sometimes Haskell can be as frustrating as hell (yes, cabal, I am thinking of
you). It can be frustrating also when writing a bit of useful code took a
while because of the never ending (for me) learning curve. However when I am
in the flow with Haskell, it feels like my 30+ years of Lisp experiences, but
with a stronger language. It has become a cliche about Haskell's type system
guiding you away from bugs, but it is true. I never had that feeling with
Common Lisp and Scheme (but I have not tried strongly typed Racket yet).

~~~
morkbot
That's a bit of an off-topic but may I ask, why Haskell over Clojure. What are
the differences? You partly asked that in the 2nd part, but I would like to
know more. I never did any serious FP so would love to know where to start:
Scala? Clojure(Script)? Haskell? F#?

~~~
bkirwi
Here's an article that was on the frontpage recently; some reflections from a
Clojurist that switched to Haskell:

[http://bitemyapp.com/posts/2014-04-29-meditations-on-
learnin...](http://bitemyapp.com/posts/2014-04-29-meditations-on-learning-
haskell.html)

------
SeanDav
Not at all trying to diss the OP, who wrote an interesting article, but if
anything, this has put me off FP a bit. It really does seem like a lot of
effort to go through for unclear benefits.

I have no doubt that learning FP will make me a better programmer (so perhaps
it is worth it for that alone) but it seems to me I should rather spend those
hours learning more data structures, or algorithms or machine learning.

Not sure I get it.

edit: it appears partially to be a definition problem. Exactly what is meant
by FP and in what language, is a large part of the question.

~~~
JackMorgan
I'm not sure what part of reducing a codebase by 2/3rds but with double
flexibility is an "unclear benefit". Imagine if you could do that with a C# or
Java library, people would be freaking out. Or getting almost all the safety
of unit tests without writing and maintaining unit tests! That's awesome!

You want to be a lot better programmer? Go through SICP! It'll cover FP, data
structures, interpreters, algorithms, and OO. You think you know OO now? I'd
wager the chapter on OO will blow your socks off with awesome stuff you can
use right now. And you'll learn FP enough to give you a taste of what's
possible in the more powerful languages like Haskell.

Rather than sit around trying to figure out if it'll be worth it, just do it.
I've never heard a programmer who has learned it who has said it was a waste
of time. So then, what are you waiting for? No study will ever prove its
better, just like no study proved Java was better, or C++ was better, or C was
better. It's impossible to prove. Was each objectively better? In some ways.
Is Haskell objectively better than all of them? Yup. There's all the proof
you're going to get: opinions of those who know all of them. You either trust
that, or you stay comfortable and fall behind.

------
brudgers
It's not that I don't think that programming in a functional style isn't a
good idea , it's just that the discussions about functional programming and
the languages people use to implement its style so often suggest:

    
    
       If you use language 'x', then using
       mutation is wrong.
    

and recently, I've been thinking about the practically important but socially
awkward question:

    
    
       What language is best for implementing
       mutable state?
    

By which I don't mean:

    
    
        What language makes avoiding mutable
        state impossible?
    

because given my skill set on some absolute scale that encompasses Knuth, I've
got big fish to fry. Trying to maintain ideological purity is a distraction at
best and an impediment at worst, if I am ever to see an _[m42]_ and have a
solid intuition about its solution.

Even the most rousing chorus of 'Onward Christian Soldiers' isn't going to
help me implement Hoare's Quicksort in Clojure. Consing and filtering are
great, but they miss the idea of working in-place. Racket's built in O(log
n)priority queue isn't a substitute for a traditional O(1) queue
implementation:

    
    
       +-------+
       |   | o-|------------------+
       +-|-----+                  |
         |                        |
         v                        v
       +-------+    +-------+   +--------+
       |   | o-|--->|   |o-|--->|   | nil|
       +-|-----+    +-|-----+   +-|------+
         |            |           |   
         v            v           v
        'a           'b          'c
    

The built in priority queue is mutable anyway.

The illustration of queues in Racket isn't rendered from whole cloth. If one
searches the Racket documentation (depth first is implied?) the only hit for
'queue is the priority queue which lives in the 'data library [and again, it's
still mutable and not thread safe]. But the real problem is that providing
Racket implementations on Rosetta code is one of those ways Racketeers are
encouraged to give back, and the implementation of LIFO on Rosetta Code shows
the priority queue, rather than an actual queue, in part because using 'mcons
is considered taboo under functional programming mores. It's a socially
acceptable answer, rather than a correct one.

Some things just have to be to be mutable in order to get built in a way that
will be useful when dealing with large tables when the first test of usability
is getting built in the first place. It's not that playing with dangerous
objects ought to be encouraged, it's that it there's nothing wrong with a
little dynamite now and then for removing stumps when the alternative is
lifting the grinder to the top of the cliff with a crane. All that really
matters is acting in accord with the fact that, yes, we're using dynamite.

There's a continuum between Coq and MMIX. A good functional programming
language allows refactoring a solution from right to left. It doesn't pretend
as if there isn't a right wing or that it doesn't matter politically.

~~~
takeoutweight
I suppose I can only speak for myself, but as a functional programmer I would
never ask you to give up mutation completely.

I do think it's nice that most FP languages give us pure functions and
persistent data structures that are easy to use and relatively performant, so
we don't have to go out of our way to provide a pure (by construction)
abstraction when we want to.

The key idea is to be honest when you are asking for mutation. Haskell would
likely be far on the "left wing" (or right wing?) on your political spectrum
but you can do mutation whenever you please as long as you're honest and mark
it in the types with something like IO, State, or ST (Clojure does something
similar in spirit with 'transient'). There is even unsafePerformIO if you are
absolutely sure that you are wrapping an impure computation in a way that you
know looks pure from the outside.

Purity isn't promoted because it's a virtue. It's that pure expressions
generally come with nice commutativity and idempotency laws which give you the
ability to refactor code while remaining confident you won't change its
meaning or alter the behaviour of distance subsystems. It's worth preserving
those properties when you can.

~~~
brudgers
Maybe, what I am thinking is that a language which makes it easy to program in
a functional style, should make it equally easy to program in an imperative
one. By extension, this may mean that a good language for functional
programming ought to make it easier to program imperatively than languages
designed to facilitate imperative programming.

Of course, this begs the question of what is easier and harder and better and
worse. There's a case to be made that Haskell's monads make imperative
programming easier. It's essentially a mathematical argument - rather
abstracto-theoretical versus the sort of concrete arguments that get advanced
to avoid discussions of why it might be better to reason with lambda-calculus
versus using von-Neumann as a model.

To put it another way, being able to abstract away von-Neumann into
mathematics is useful. But the von-Neumann model is useful because it is a
model that we can easily get our heads around.

~~~
jackpirate
If you asked a Haskell expert what their favorite imperative language is,
they'll probably say "Haskell."

That is because it "makes it easier to program imperatively" more than any
other language I've met.

~~~
trobertson
Only after the learning curve, though. It isn't immediately approachable as an
imperative language.

~~~
the_af
Yes, but suppose you could write the same program in two languages, a classic
imperative one, and a purist and difficult FP language.

For the sake of argument, let's assume the classic imperative language is
easier to approach for rookies. If it's also the easiest language _to write
bugs and make mistakes with_ , wouldn't the "harder" FP language still be a
net win? As long as its learning curve isn't unapproachably steep -- i.e. so
steep that your time to market becomes awful -- what is the advantage of the
imperative language's ease to hit the ground running and writing lots of bugs?

~~~
brudgers
If language 'a' lets a person write a program with 'b' bugs in time 't', and
language 'aa' lets the same person write the same program with 'b' bugs in
time 't-n' then there is a clear net win for all 'n' > zero.

If 'aa' also has the advantage of providing semantics for producing
significantly less buggy code in time 't-n-m' at some future time then that is
also an advantage but a distinctly different one and one which can be deferred
[and probably will be given a significant learning curve].

The first step toward the modern automobile was the 'horseless carriage' not
the Countach.

~~~
nightski
It's greatly overstating the learning curve. It's possible to pick up Haskell
by simply writing a few small applications tackling different parts of the
language in each one. This can be done in a few months. Not to mention there
are now numerous resources available for free such as learn you a haskell,
real world haskell, and countless blog posts.

~~~
dllthomas
I hear the Wikibook also has a good introduction.

------
analog31
Ask HN: As somewhat of an old timer, I have a couple of questions about FP,
not really worthy of creating their own thread:

1\. I learned a rule (in my Pascal textbook), "avoid globals." Is FP just an
embodiment of that principle?

2\. I do a lot of programming involving hardware, often homemade. Hardware has
state, such as whether a lamp is turned on or off. Does this just mean FP is
inappropriate, or are there techniques out there that accrue the benefits of
FP in systems that necessarily have state?

~~~
noelwelsh
1\. I think "avoid globals" is a reasonable way into FP, but FP itself
involves a lot more than just avoiding coupling via global state. I would say
the main components are

\- nested definitions;

\- lexical scoping;

\- first class functions;

\- static typing; and

\- a whole bunch of programming techniques (e.g. monads) that have grown
around them.

2\. You certainly can use FP ideas in low-level programming but you'll have
difficulty finding a FP language that targets your hardware. There are a few
small Scheme implementations that might work. Rust is viable if we're talking
32-bit CPUs, not 8-bit.

(I imagine the Rust developers would not claim Rust is a functional language,
but it has absorbed a great many ideas from functional languages. I prefer to
talk about modern programming languages instead of functional programming
languages. Rust, Haskell, and Scala are all modern and have many features in
common. Only Haskell claims to be a pure FP language though.)

~~~
vram22
>\- static typing;

I'm not an expert on the theory or design of programming languages, but isn't
static typing orthogonal to FP?

~~~
_Robbie
I will discuss Haskell, since I am not very familiar with other FP languages.
In Haskell static typing is more useful than in other languages. This is
because in Haskell the type signature of a function gives an upper bound of
what the function does. In an impure language, a function may change any
accessible mutable values and/or perform IO. These possible side effects mean
that in an impure language the type of a function is a very weak indicator of
what the function actually does.

~~~
vram22
So you're saying that static typing helps FP and hence is sort of a part of
it?

Thanks for the answer.

------
virtualwhys
Suprised that the year ended with one language and not another, particularly
given his background.

This could be indicative of a "good enough" FP trend where the net affect of
language authors cherry picking FP constructs does _not_ , ironically enough,
result in significantly increased adoption rates for those FP languages that
are at the forefront of FP R&D.

Case in point: the recently announced Swift appears to have a decent grab bag
of FP candy that will immediately appeal to legions of iThing app developers.

In short, it may be that Haskell, and particularly Scala (fending off Java 8,
Kotlin, Groovy, and Clojure) will be fighting for scraps until one of them
comes up with a killer stack that launches them out of niche status into the
mainstream. Could be awhile yet...

------
pron
I used to like functional programming. Now I think that it's -- more often
than not -- a solution in search of a problem. I can understand some of the
things FP gets you (although those come at a cost, which I'll get to later);
I'm just not so sure these are the things we need, or that FP is the best
solution for them.

One is code reuse: yes FP code is definitely more reusable. The problem is
that the kind of code it enables reuse of more than OO is very small, simple
loops. This is never a big issue. Writing the same 4 line method -- which
could have been abstracted with a monad -- 10 times in a 50-150K LOC project
is never a big problem, and these methods rarely contain bugs. On the other
hand, OO code is often easier to refactor and modify. Sometimes -- in Java for
example -- dynamic linking combined with OO, lets you modify/add functionality
without even re-compiling existing code. Heck, it let's you add and load new
polymorphic type implementations at runtime. It is much more malleable than FP
code.

Another is state management: yes, FP is one solution to the problem of
managing state, especially in a multicore environment. But it is neither the
only solution, nor is it the best. The Clojure solution of -- for lack of a
better name -- "transactional" mutable state is simpler than the pure FP one,
and just as safe. I.e. there are ways to make side-effects safe without
restricting them so much that they become a nuisance (after all, all software,
possibly with the exception of compilers, exists for the sake of its side
effects).

Finally (and I've said this before on HN), a language like Haskell discounts
the very useful choice of reasoning about your code after it runs, favoring,
instead, all-upfront reasoning, often at the expense of facilitating the
former. There are some domains where figuring everything up front is very
important. Others, where trial and error is far more productive.

So pure FP increases code reuse, but of code that's not that important to
reuse. It helps deal with the hard problem of state management, but other,
simpler solutions exist. Finally, it makes it hard to "feel" how your code
runs, to debug it, to profile it, and more. I think it is based on the premise
that if programming could be made more formal -- more _mathematical_ , if you
will -- it will become easier/"better". But that premise has not been shown to
be true. The lack of magically bug-free, FP OSs, drivers, control software,
and large applications, shows that even the biggest supposed benefits of
languages like Haskell, are yet to be demonstrated in the real world.

EDIT: Just to clarify: Unfortunately FP does not have a definition, so, when I
was saying "FP", I meant "FP as the article's author practices", which means
"statically typed, pure FP". FP using Java streams, FP in Clojure/Erlang, and
FP in Haskell mean very different things.

~~~
cageface
_The lack of magically bug-free, FP OSs, drivers, control software, and large
applications, shows that even the biggest supposed benefits of languages like
Haskell, are yet to be demonstrated in the real world._

I've been reading religious advocacy of FP for almost 15 years now and yet
there still don't seem to be many non-trivial apps written in any of these
languages. Certainly many individual features of FP have been adopted to good
effect in more mainstream languages but commercial Haskell or OCaml apps are
still conspicuously thin on the ground. I think at this point it's up to the
FP advocates to back up their claims with results. I'm sure there are a lot of
programmers that would happy to roll up their sleeves and learn something new
if it truly would make them 3x more productive.

~~~
chiurox
How about WhatsApp's backend being extremely scalable because it was written
in Erlang from the start? Or even Twitter that rewrote much of their backend
in Scala to deal with scaling issues (I'm not saying that Rails isn't
scalable, I don't want to start a war over this issue; the important thing is
they saw a problem and solved it) while contributing many many open sourced
libraries for our use?

Foursquare uses Scala extensively. LinkedIn is using Scala extensively for its
new projects. The commercial and successful use cases for Scala are widespread
at this point. For Haskell and OCaml it's going to take a while.

~~~
pron
Well, when people say FP they mean different things. The Erlang/Clojure kind
bears little resemblance to the Haskell/scalaz sort discussed in the article.
Neither does most of the Scala code written at Twitter (which is mostly OO
with a sprinkling of functional).

~~~
tel
That's hardly true. Erlang's event loops are based on a very similar kind of
state encapsulation as Haskell's state monad. Really Erlang is littered with
explicit monadic patterns but lacks a good system for abstracting over those
patterns so you just call them "OTP" instead of a monad.

------
mncolinlee
The one question I wish this article answered is: what specific, quantifiable
benefits could I get from using a real functional language RATHER THAN merely
reactive extension libraries to an imperative language.

The point many programmers are at is far removed from diving into Haskell and
hard math in functional languages. Many of us are still learning why to
compose observables for multithreading. From a application programmer
perspective, what could we gain by diving into FRP completely?

If Scala is the gateway drug, then the dealers need to do a better job
explaining what the hard stuff actually does for us.

------
briantakita
> Realisation: Abstractions

Objects are coarsely grained abstractions. Separating function Modules from
the Data allows more opportunity to be DRY, better performance, and more
complexity scalability.

> Realisation: Confidence. Types vs Tests > In Ruby, that often meant testing
> it from every angle imaginable, which cost me significant effort and negated
> the benefit of the language itself being concise.

This is largely a cultural artifact from the history of the Ruby & Java
communities.

We are discovering that is is more useful to have your tests written from a
black box perspective (in any language). White Box Testing is less useful and
causes the architecture to be locked down. White Box Testing should be a rare
occurrence.

From my development practices, Static + Strong typing helps with performance &
debugging failing tests, but not much else. It imposes rigidity in the
architecture & delays my development feedback loop.

I know that this is a matter of taste & I will catch much flak for my opinion
as it conflicts with other peoples' taste, but it's my truth :-)

------
IvarTJ
How well does deploying Haskell web applications to a low-memory VPS work? My
experience with the Play framework tells me that Scala is out of the question.
Presumably using Haskell involves cross-compilation, considering the memory
usage of GHC compilation.

~~~
dllthomas
I've been deploying Haskell web applications to a 1G and a 512M VPS, and both
have been working fine. Initially I was able to build on the boxen, but more
recent libraries/compiler runs out of memory building some dependencies.
Obviously that wasn't ideal anyway since it was taking up resources the live
site could be using, although none of the relevant sites are supporting a ton
of traffic. Building on my local machine and pushing up the executables has
been working just fine, though.

------
Kiro
Would you recommend starting with Scala before Haskell if one want to learn
FP?

~~~
chriswarbo
No. Scala does some interesting things, but it adds a lot of complexity in
order to interact with typical JVM code.

Haskell doesn't have that kind of baggage, so at its heart it's a very very
simple language (Lambda Calculus + algebraic datatypes + typeclasses). There
are a bunch of extensions, but they can be mostly ignored while getting to
grips with the basics.

Programming in Haskell can involve a lot of unfamiliar concepts like monoids,
functors, monads, etc. but these are just the APIs used by libraries; the
language itself doesn't care about them (except for "do" notation). Just like
you don't need to understand design patterns to learn how Java works.

~~~
VLM
And yet that complex JVM interaction makes one possible way to "get toes wet"
is to wrap existing lower level java processes (and libraries and things) in a
larger functional wrapper. Top down. Assuming you have some experience,
confidence, or sample code in java that you can use or understand in the
problem domain. So rather than trying to find a way to use recursive
functional definition of a factorial in your code (bottom up) it Might be
possible to work top down and make the "main loop" or whatever of your java
program a functional construct of some sort.

I am in no way claiming this is the best way, only way, or even a good way to
learn FP concepts but it is a possible way to at least get feet wet, plus or
minus your personal characteristics. It is merely an alternative to the
extremely popular nearly universally pushed educational strategy of bottom up
introduction of FP.

~~~
platz
Because Scala is a hybrid language, I feel it doesn't really try to teach FP,
but some amalgamation of the two. So you'll end up thinking about case
classes, traits, companion objects, unapply, etc... it's a way to solve
problems in a unique way, but in comparison with the other more traditional FP
languages, it doesn't present the same feel and can obscure which features are
the ones necessary for FP - which is important to know if you're specifically
trying to learn FP.

~~~
VLM
You are technically correct in your observations, but I think we're both stuck
in a classic "glass is half empty" "glass is half full" observational trap.
Both the good news and the bad news simultaneously about a hybrid language is
you can implement the same solution two different ways.

If you did both intentionally for educational purposes, it might be fun. I
like the many "koan projects" and a side fork that focuses intentionally on
doing something two ways might be interesting, if its not already been added
while I wasn't looking.

------
naland
>I've been coding since the age of 8, so 26 years now. >I started with BASIC &
different types of assembly then >moved on to C, C++, ...

So to 68002 he had nine and a half or ten, here the article it's enough for
me— even I'm interested in FP, but too old.

