Hacker News new | ask | show | jobs
by karmakaze 941 days ago
If we taught functional programming first, there's a log we can do without. We don't need variables that vary--only reference names that are assigned once within a scope. We can also eliminate loops and associated off-by-1 mistakes using map, reduce, etc.

This of course puts different 'hard' things up front like applying a function over a collection of data, but that's one that scales well, IMO.

But we also hit recursion sooner, that could be a difficult hurdle as it requires a big 'trust me this works' until a better understanding is gained. Again this scales better as it teaches making a smaller instance of the problem to solve at each level/layer that's universal in decomposing problem into similar and/or dissimilar parts.

4 comments

> This of course puts different 'hard' things up front like applying a function over a collection of data, but that's one that scales well, IMO.

I think this depends on the audience. If you want to teach programming to people with less talent/passion for math, I believe you can have more success with procedural/imperative programming, which IMHO requires less abstract thinking than functional programming.

I'm on the fence about this, which is why I'm interested in hearing about cases where FP is taught as an intro. I sort of suspect that the younger folk (as in children) may be more comfortable with FP when you tell them that this phrasing does such-and-such without further explanation or understanding and be able to apply it. Grown-ups will question why a self-referential function can work at all and perhaps get hung up on it until they grasp recursion.

In short it requires more abstract thinking to understand it, but understanding isn't necessarily required to apply it effectively.

I think in some ways functional programming is easier to understand conceptually; it's a closer match to how I think about things. Like if I want to transform an array, I don't think "I want to create a new, empty array and then loop over the first array and call a function on each value and put the result in the new array", I think "I want to run this function on all the values in this array" (same for filter, same for find...). Reduce is a bit trickier, perhaps, but if you start with the example of finding the sum of all the values in an array that probably lays a decently intuitive foundation for it as well.

So yeah, I don't consider myself a particularly math-y person, but I find functional programming to be a more straightforward and less fiddly way of going from a design in my head to something the computer can execute.

> I want to run this function on all the values in this array

I think most people get lost on the "run this function".

My impression from high school math classes is that very few people understand the concept of a function in abstract terms. Like, they will learn that sin(90) = 1, because it's a particular, specific function, but they don't understand functions as "first class citizens" in the sense of "apply this function to this array". That seems like a new plane of abstraction to which many never get.

Hmm,that could be--I've been doing this long enough that I've probably forgotten some of the things I struggled with. It feels like it would work to say, "Here's this graph of a sine curve, and what that means is if you take a value you want to find the sin of on the X axis, and trace upwards until you get to the line, and then over to the Y axis, that's the sin of that X value [draw a couple of examples] and if you have a bunch of X values that you want to calculate the sin of, you can put them in an array A and use A.map(sin) and the result will be a new array with the corresponding sin values [draw input array A with the same values as the Xs selected on the graph, A.map(sin), and a new array with the corresponding Y values as from the graph]"

Sure, it won't work for everyone, but I'm guessing (hoping?) that "functions as first class citizens" won't seem that weird to people who have never worked with a language where they weren't

I think the hard part is trying to imagine 'run' combined with 'function'. If you present a picture of a collection of data, a function that maps input values to outputs, and a picture of the output collection of data, that's fairly easy to grasp. The difficulty comes from bothering to describe how the computer does it by running a first-class function on the data. And that's the part of understanding that could be delayed IMO. Treat more of programming as declarative rather than procedural.
> If you present a picture of a collection of data, a function that maps input values to outputs, and a picture of the output collection of data, that's fairly easy to grasp. The difficulty comes from bothering to describe how the computer does it by running a first-class function on the data

I think your describing the solution to the problem: this is how (pure) functions are introduced in high school or university, and that's also what they fundamentally are defined like!

Of course no function in a computer program is really a black-box, but introducing

  f: A -> B
as a black-box gets you far enough for all practical purposes! Defining the properties of a mathematical function and the related categories of injective, surjective and bijective maps between sets is all one needs to know about a (pure) function.

And when it comes to e.g. f(x)=sin(x), how many programmers or high school students could write down an algorithm to calculate e.g. sin(1/4) out of their head?

I know it's a long-solved basic algebra question, but treating functions as black-boxes can be perfectly fine.

When it comes to programming, of course, shared mutable state (i.e. lexical scoping) and how actual functions in some language relate to these concepts is the meat of the problem.

But even this space can be explored without knowing complex FP concepts. And JS is a great language to do so :)

Any JS programmer learns about the difference between a pure function and an impure "function" in some intuitive fashion sooner or later, because lexical scoping is so much at the heart of the language.

So much that day-to-day work can even include a fair amount of shifting around logic between shared mutable state, function parameters and captured closures.

> And then came JavaScript. Well, along came real computer programming. It could have been Python or some other language, I think, but the transition to writing programs, even short bits of code, took the wind out of the students' excitement.

The big change here is the procedural (time/execution steps, mutable variables) nature of these languages. Functional programming can be taught from a declarative perspective which is more along the lines of HTML/CSS.

That's what my university did.

First semester was Haskell and Logic (truth tables, state machines), and some other stuff

Second semester was Java, and some other stuff

Were there many that seemed to have more difficulty with this introduction than if they were shown a procedural language, that you noticed?

My hunch is that to complete beginners a declarative approach is simpler than a 'play computer' mental simulation to coding. We shouldn't be initially shown what's effectively a Turing machine and save that for a later Theory of Computation or intro to procedural languages.

I am building an IDE for functional JS. It can visualise a call tree of a program, helping to understand execution of recursive functions

http://leporello.tech/