
Mostly Adequate Guide to Functional Programming in JavaScript - codecurve
https://github.com/DrBoolean/mostly-adequate-guide
======
crazygringo
For a long time I've been looking for a guide to functional programming,
applied to common real-world web examples, but still can't find one.

E.g. when most of the code I write is database queries, performing business
logic, calls to memcached, handling error cases/messages, validating input,
and then outputting data in various formats (JSON, HTML templates, etc.) --
how/where does FP help with that?

Is FP more a paradigm for computationally intensive programming? Back-end web
programming? Front-end? I come across "FP is good" all the time, but I've
never found any kind of resource to help me understand the tradeoffs between
FP and non-FP, where it makes sense to use it and where it doesn't. Or any
kind of FP tutorial on how to build, for example, a basic web CRUD app.

~~~
Retra
Functional programming is not for back-end web programming or front-end web
programming. That's like asking if calculus is for making better nails or for
making better screws. Or if a 68K processor is for doing taxes or for doing
word processing.

It has nothing to do at all with what kind of thing you are building, it is a
general means of expressing common patterns in programs. Much of the reason
people like FP is because it provides a high degree of code reuse in
standardized forms, and it does so with a good bit of terseness and
flexibility. Just about everything else in the FP world is about optimizing
safety, performance, and reliability without giving up these benefits.

When someone says "FP is good," it's analogous to saying "well-commented code
is good." As in, it's good everywhere you have the time to do it correctly.
(There just happens to be a lot of debate about how to do it correctly.)

~~~
edvinbesic
For those of us non-yet enlightened, I keep reading these kind of comments and
walk away more confused.

Sure, I get what it is but what I don't get is how I would use it in my world
of mutating data and side-effects.

~~~
agumonkey
So far I believe side-effects as we think of them are unavoidable[1]. But they
can be reduce to a minimum (the maximum being writing programs as a big set of
global variables, and jumping GOTOs between mutations). Using functional style
avoid a lot of nasty side effects like unnecessary temporaries, uninitialized
values and their modification afterward (local assignments or across
procedures). This is a thing one can do in C, whereas in FP languages, you're
constrained to write this way, giving a culture of combinators and patterns
(tree rec, map, fold, streams, monads, ..) hugely solid and tiny, thus
reusable.

I understand what you mean, because even though I love FP a lot, I still
struggle to conceive whole systems (other than simple map-filter dataflow
ones) this way. So far I keep the FP principles for small pieces, hoping later
on I'll find a way to close the gaps.

[1] John Backus tried to design purely functional languages a long time ago
and he hit the IO wall (he mentions it in some article). Haskellers had issues
at first and found that Monads were a nice functional way to express IO-like
logic. It's still something weird, a lot less clean than purely functional
expressions to be evaluated.

~~~
edvinbesic
The 'IO wall' as you put it is the main thing I have not been able to wrap my
head around. Most of the examples I have seen of FP-implementation-of-X leave
this bit out, or at best is a passing mention left as a 'reader exercise'.

Most of us probably already follow best practices in terms of small functions,
no global state, promises, composability etc. But at the end of every chain I
have a db query and most of those mutate some data or other.

Hopefully some day it clicks.

~~~
codygman
> Hopefully some day it clicks.

While you wait for that, try writing useful code despite not fully
understanding it.

Tell me what you think of the following code examples:

    
    
        > sum . take 2 $ [1,2,3,4,5]
        3
        > -- now lets pretend we have a list of numbers we got from the DB
        > let mockDBResponse = return [1,2,3,4,5] :: IO [Int]
        > -- first lets try the exact same code as above
        > sum . take 2 $ [1,2,3,4,5]
        3
        > sum . take 2 $ mockDBResponse
       
        <interactive>:46:16:
            Couldn't match expected type ‘[c]’ with actual type ‘IO [Int]’
            Relevant bindings include it :: c (bound at <interactive>:46:1)
            In the second argument of ‘($)’, namely ‘mockDBResponse’
            In the expression: sum . take 2 $ mockDBResponse
        > -- what to do? Use <$>
        > import Control.Applicative ((<$>))
        > sum . take 2 <$> mockDBResponse
        3
    

1) Applying pure functions to pure functions

    
    
        sum . take 2 $ [1,2,3,4,5]
    

2) Applying pure functions to monadic functions that implement fmap of the
Functor typeclass

    
    
        sum . take 2 <$> [1,2,3,4,5]
    

When I noticed that adding brackets around $ allowed me to apply pure
functions to monadic ones a lot more made sense to me.

------
Roboprog
The author should probably have mentioned in the Currying section that it's
roughly analogous to what OOP people call dependency injection.

Rather than a "class" with one "do it" method, which also has a constructor to
initialize configurations (or worse, a bunch of "setters"), just make the
configuration (or other "dependency") values the leading parameters of a
function. Then, partially evaluating the function to supply those values does
the same thing that "dependency injection" does, only without the logorrhea of
a class.

~~~
thesagan
Thank you for that analogy, I think you might have saved me a bit of time
wrapping my head around the FP "paradigm".

------
elliotec
Also see Functional JavaScript [1] by Michael Fogus.

[1][http://shop.oreilly.com/product/0636920028857.do](http://shop.oreilly.com/product/0636920028857.do)

------
n0us
Something I've been wondering for a long time that no one seems to be able to
explain is "what the fuck is a monad?" and why is this seemingly the one
question about programming that is inadequately answered

~~~
chowells
I'm willing to bet you've read 10 plain-english perfectly-adequate
explanations of monads that explain them fully, and you've rejected them
because they don't seem hard enough.

A monad is an abstraction pattern that, as applied in typed functional
programming, has three parts.

1\. A type constructor that takes a type and returns an type. Enough languages
have an Optional construct now that this should be sensible to anyone paying
attention.. If Integer and Optional<Integer> are types that have values,
Optional is a type constructor.

2\. A function for injecting a value in an appropriate manner. To stick with
java-ish syntax, it'd look like Optional<T> inject(T x) { ... }.

3\. A function for binding a function to a value with appropriate types.
Optional<R> andThen(Optional<T> x, Function<T,Optional<R>> f) { ... }. This
function has a couple restrictions on what it's allowed to do which are called
the "monad laws". It's not really worth burying yourself in them. The
important part is that they have the effect of requiring inject and andThen to
do the absolute minimal thing that works sanely.

This really isn't complicated. It's a super-basic pattern. It keeps getting
reinvented over and over in languages with first-class functions.

So why do you not hear about it outside of typed functional languages? Because
very few languages give you the flexibility to _work_ with this abstraction.
In Haskell or F#, you can write code that works with any monad. In Java or
Rust, you can only write code that works with a specific type. The missing
abstraction capability makes the abstraction academic only. And since it's so
simple, there's nothing in particular to be gained by talking about the
abstraction when you can't use it.

People have made a huge deal out of monads, but they're really not
complicated. Thinking they're hard or hold the secrets of the universe is like
thinking the Iterator interface is hard or holds the secrets of the universe.
Sure, maybe a language has some syntactic sugar to make it easier to work with
them (do-notation in Haskell, for loops in Java). But it doesn't mean there's
anything complicated going on.

Note the things absent from this response: IO, side-effects, purity,
sequencing, basically any use case. None of them are related to the definition
of monads. None of them require monads. Monad is an _abstraction_. It doesn't
let you do anything new. It just lets you share vocabulary (and code in more
expressive languages) between many disparate areas.

~~~
tome
> In Haskell or F#, you can write code that works with any monad

F# doesn't have higher kinded types, so I doubt this is true.

------
noelwelsh
Nice illustrations, and a worthwhile project. I'd like to know what has
motivated the sequence of topics, as things I consider fundamental (e.g.
structural recursion) don't seem to get a look in. This is judging just by the
TOC.

(For all the innovation in the training delivery of programming training there
seems to be little attention paid to the pedagogy. This is not really a slur
on this book (I haven't looked in detail; hence the brackets) but too many of
the online training providers just use the same old ineffective curriculum
they were exposed to in undergrad.)

------
cnp
Seriously impressed with the communicability of your examples. A+, will share
this around.

------
amelius
Does it treat lazy evaluation? Also, how efficient will the resulting code be,
if these conventions are used?

------
dozzie
> We'll use the world's most popular functional programming language:
> JavaScript

Then you won't be doing functional programming. You will be doing "somewhat
functional programming" at best.

~~~
lojack
Is there a reason why you can't do functional programming in JavaScript.
Unless I'm mistaken, there isn't anything about JavaScript that explicitly
prevents you from doing functional programming.

Even then, I think we all understand that the OP isn't trying to be strictly
pure and is simply trying to explain the concepts in a manner that those used
to imperative development can easily digest.

~~~
dozzie
1\. No pattern matching. Libraries can't help here, it's a syntactical and
semantical issue.

2\. No product types. You can emulate those, but it's awkward.

3\. No recursion over lists. You can emulate this, but it's awkward.

4\. It's difficult to write code that is efficient, yet is side-effects free.
Good luck with prepending an element to a list.

About emulation, you can emulate closures on Turing machine, though it doesn't
make Turing machine a functional language. Lack of the aspect is simply lack
of the aspect.

And no, JS doesn't _explicitly_ prevent functional programming (or rather,
some aspects of it). It does so _implicitly_.

> OP isn't trying to be strictly pure and is simply trying to explain the
> concepts in a manner that those used to imperative development can easily
> digest.

It's like trying to show how to do OOP in C. It's a different paradigm than
the primary of the host language, so any educational aspect will be severly
diluted, to the point of being useless to anybody who doesn't already know
functional programming.

~~~
lojack
> It's like trying to show how to do OOP in C.

Actually, I'd think that would be a super valuable to a C developer. Learning
to implement OOP patterns in C would provide practical patterns that can help
architect C software. For non-C developers, it'd also provide fundamentals of
how OOP actually works. C developers have been implementing OOP patterns since
well before C++ existed.

There's lots of resources, and practical examples of this. GObject provides an
object system used by both Gnome and GTK. Check out "Object-Oriented
Programming With ANSI-C" for a book on the subject.

~~~
stream_fusion
It's arguably faster and of more benefit to learn OO in an OO language, and
then work backwards to figure out ways to implement those strategies in C (eg.
polymorphism using structs with arrays of function pointers, or win32
send_message constructs).

It's similar with functional programming. Figuring out folds, pattern matching
and monads is probably easiest in haskell or Ocaml/F#. The decision to apply
those techniques in other languages without native support then becomes a
judgement about the benefit.

