Why start with computation as a sequence of operations? It might be equally useful (maybe even more useful for some students) to start with computation as a series of reductions e.g. with combinator logic.
Because that's how a computer actually works, and the sequential execution concept is something that is intuitive to anyone who has followed a schedule, a recipe, been taught how to tie their shoelaces, ... , in essence, done any sort of living.
So what? That is kind of like saying that people need to understand how an airplane works in order to ship a package overnight. Sure there is value in understanding how a computer works, and that will probably be taught later in the curriculum; but teaching students how to think abstractly is far more valuable.
"the sequential execution concept is something that is intuitive"
So is the concept of reducing one expression to another; we teach algebra as exactly that long before we teach anyone how to program.
Sequential instruction is learned before expression reduction in real life...
So what? That is kind of like saying that people need to understand how an airplane works in order to ship a package overnight.
But people DO need to understand a bit about the process of shipping a package, if they want to estimate when it will arrive, or if they want to be able to read the online tracker, or even know that they must bring the package to a particular place before fedex will ship it. Or if the package does not arrive, what would you have to do to find it?
Generally speaking, understanding how a computer works is important to programming because the essence of programming is mapping a real problem onto the available computational hardware.
Not that I want to argue against learning about expression reduction, I would agree that should be done sooner than later, but it's not an argument against learning sequential algorithms.
I TAd a CS101 course in grad school. I saw a number of students try do something like this:
func(if(x == 5) foo else bar)
In other words, treating an "if...else" statement as something that can be reduced to a value. This frustrated the students because it did not compile. We had to train them to think in terms of sequential execution, despite the fact that they did not become any better at programming in the process (worse, they had to un-learn a perfectly valid way to think about programming -- only to have to re-learn it later if they took the programming languages course).
What language was your class using? There are so many ways to do what the students wanted to do, be it the tertiary function or a lambda function or even, defining a method/function like (Ruby):
def foowiz(x, threshold = 5)
if x == threshold
foo
else
bar
end
end
And then a call to func(foowiz(x)) would work - even in an OOP language like Ruby.
What did the students need to unlearn?
In the intro CS class I took an age ago, we had to implement OOP as a final assignment in Dr. Scheme, which is a derivative of LISP that is most assuredly a functional language rather than OOP. That did not mean I had to unlearn how lambdas and tail recursion worked.
Why did they have to "un-learn" anything? What they should learn from that experience is that the particular tool they were using did not have a feature they expected. Any reasonable teacher should explain that. It's important because often, extra features come at a cost and while some of those costs have been paid permanently by researchers and software developers of the past, others still require tradeoffs.
Thinking in abstract terms is all well and good until you actually have to run code in a real environment to solve a real problem with the tools you have available.