Hacker News new | ask | show | jobs
by zahlman 673 days ago
> I am under the impression that people start programming, by and large, with imperative for/if style => so the imperative style is readable by more people.

IMO, this is a simple consequence of technology moving faster than society. There are still instructors out there who learned to program in an environment where the go-to options for imperative programming were C and FORTRAN; the go-to options for other paradigms (if you'd even heard of other paradigms) were things like Lisp, Haskell and Smalltalk; and CPU speeds were measured in MHz on machines that you had to share with other people. Of course you're going to get more experience with imperative programming; and familiarity breeds comprehension.

But really, I believe strongly that the functional style - properly factored - is far more intuitive. The mechanics of initializing some output collection to a default state (and, perhaps, the realization that zero isn't a special case), keeping track of a position in an input collection, and repeatedly appending to an output, are just not that interesting. Sure, coming up with those steps could be a useful problem-solving exercise for brand-new programmers. But there are countless other options - and IMX, problem-solving is fiendishly hard to teach anyway. What ends up happening all the time is that you think you've taught a skill, but really the student has memorized a pattern and will slavishly attempt to apply it as much as possible going forward.

> Futhermore, in JS, the functionnal style is less performant (nearly twice on my machine, i assume because it do less useless memory allocations)

Sure. Meanwhile in Python:

    $ python -m timeit "x = []" "for i in 'example sequence':" "  x.append(i)"
    500000 loops, best of 5: 796 nsec per loop
    $ python -m timeit "x = [i for i in 'example sequence']"
    500000 loops, best of 5: 529 nsec per loop
... But, of course:

    $ python -m timeit "x = list('example sequence')"
    2000000 loops, best of 5: 198 nsec per loop
Horses for courses.
3 comments

Functional programming is more intuitive for many pure data transformation tasks.

It's not more intuitive for the entire system.

When you make a new file in a file system, you're already violating functional programming, even if you atomically create that file with all the content specified, and make it immutable.

You must construct a new file system which is like the old one, but with that file, and then have the entire system tail call into a world where you pass that new file system as a parameter, so that the old one is not known (garbage).

Unix has been the most successful system in getting partial functional programming into ordinary people's hands.

A Unix pipeline like < source-file | command | command | ... | command > dest-file is functional except for the part where dest-file is clobbered. Or at least can be functional. The commands can have arguments that are imperative programs (e.g. awk) but the effects are contained.

In the famous duel between Doug McIlroy and Knuth in solving a problem, in which McIlroy wrote a concise Unix script combining a few tools, McIlroy's solution can be identified as functional:

  tr -cs A-Za-z '\n' |
  tr A-Z a-z |
  sort |
  uniq -c |
  sort -rn |
  sed ${1}q
Nowhere is there any goto statement or assignment.
One problem I have with functional programming is that I find it hard to debug.

With imperative programming you can follow a program step by step, line by line, it can be done with a debugger, pen and paper, or in your head.

With functional programming, not so much. It runs functions. What do these functions do? Don't know, they are pieced up from someplace else in the code. And thanks to lazy evaluation, they may not even exist. In the design phase, it is mostly a good thing, as it is flexible, and pure functions are less likely to make a mess than functions with side effects, but there will be a point where the program will not behave as it should, no matter your paradigm. And that's when it becomes a problem.

It is also a problem with object programming if you abuse abstraction, in fact, it is a general problem with abstraction, but functional programming makes it the default, whereas imperative programming is concrete by default.

As for the Python example, I am a bit surprised that the optimizer didn't catch it, all three are common and equivalent constructs that could have been replaced by the most performant implementation, presumably the third one. But well, optimizers are complicated.

People think imperatively though. If I think of visiting my friend, grabbing gas on the way back, the way I'll visualize the steps is not functional.
I disagree. People are sometimes just forced to think imperatively when dealing with computers, but I usually think declarative when I design my programs.

Say if I want to filter a sequence of users and omit users below the age of 18, I'll construct my predicate (a "what"), and want to apply that predicate to create a new sequence of user (another "what").

I really don't want to tell a computer how to process a list every single time. I don't care about creating an index first and checking the length of my list in order to keep track that I process each user in my list sequentially, and don't forget that important "i++". All I want at that moment is to think in streams, and this stream processing can happen in parallel just as well for all I care.

But I also do think Python, Haskell etc. are the most expressive here with list comprehensions. It can't get more concise than this IMHO:

  users_adult = [
    user
    for user in users
    if user.age >= 18
  ]
That's quite debatable.

In this case, you first declare the end-goal - visit a friend and have full gas tank, with the actual steps to achieve them being much less important and often left to be defined at a later point (e.g. which particular gas station, which particular pump etc.). This corresponds more to functional thinking.

An imperative thinking would correspond more to "I will sit in the car, start the engine, ride on highway, stop at address X, converse with Y, leave 2 hours later, stop at gas station X" - in this case the imperative steps are the dominant pattern while the actual intent (visit a friend) is only implicit.

Your second part is how I think and how I think most people think. That's exactly what I meant.
So when you arrange the visit with your friend two weeks in advance, you first think about sitting in the car, driving out of the garage, getting on the highway, turning on the radio, parking the car, ringing the bell and this other myriad of actions, and the actual talking with the friend is just one of the actions, with no prominence over the others?

I certainly don't think like that. My main goal is to visit a friend. The transportation is subordinate, it's only a mean to the goal, an implementation detail which I don't care about much. I might even take a train instead of driving the car, or even ride a bike, if I feel like it and the weather is nice on the day of the visit.

Now reflecting on this, I think such focus on the process (as opposed to focus on the goal), exact imperative order, not being able to alter the plan even if the change is meaningless in relation to the goal, is a sign of autism. But I don't believe most people think like that.

No, we just think "I'll get in the car and drive to the hospital, talk to my sick friend, and then drive home by way of the petrol station". Higher-level, but definitely still procedural / imperative. (Then while we're driving we'll think "I'll turn left here" or "I'd better overtake that lorry", or whatever. But we don't need to plan all that beforehand; we do stepwise refinement on-the-fly.)

I think most people think more or less like that, and that it is not "a sign of autism".

You're the one that added all those conditions about exactness, about needing to replay every step (even this is a problem because steps are fractal), or not being able to change the plan. I can think imperatively and still do those :)
I dont know a lot about the brain but I do know that people that research modeling brains have used models in which there are two types of things to think: declarative things AND procedural things. See SOAR and ACT-R.

The caveat here is to which extent computers have tinted their models of a brain, but they are professional cognitive researchers so I’d give them the benefit of the doubt :)

While I think of things in a defined order, I also think in sets. If I grab a bunch of peanuts, I don't visualize grabbing every single peanut one by one, I visualize getting a bunch at the same time.
If you grab a bunch of peanuts you're probably thinking in "hand fulls", but the fact that the world and actions we take are fractal in the way we can analyze them doesn't prove one or the other.