<p>The <em>why</em> isn't necessarily related to the relative quality or benefit of the various approaches to the first courses. But some of the comments given to the question capture part of the reasons. </p>

<p>First, FP isn't precisely mainstream in industry. Most programming in the real world is <em>now</em> is done in Dijkstra-derived languages, not McCarthy-derived ones. This may change, of course, as the world starts to recognize the benefits of FP as it previously did for OOP. As the questioner mentioned FP has advantages in some important areas. But most curricula take a look at who is hiring entry level folks and what they want to see in the person's background. </p>

<p>Another reason is that most of the faculty is much more knowledgeable about those <em>mainstream</em> things than others. If the faculty went through a long program in which almost everything is built in Dijkstra-derived languages that is what they are more likely to teach beginners. OTOH, faculty (including some folks here) who went to, just to pick a name, MIT, are more likely to start in FP, but may still be constrained by the first reason. </p>

<p>Most faculty still think of FP as an advanced topic and so Let and Lambda tend to come late in the curriculum, after the students have <em>seasoning</em>. As you suggest this is not necessary, and may not be desirable, but there is a lot of inertia. </p>

<p>There is always some mental disruption when a student is asked to change paradigms, since a paradigm is built on a consistent mental model that is also relatively <em>closed</em>, not needing outside explanations. Paradigm shift is, in general, difficult, even for experts. The HS or undergraduate curriculum is short in time so most faculty are resistant, at least a bit, to require uproar in the middle of the two or four years. Much better, it is normally thought, to treat one paradigm as the main-line and any others as <em>nice but inessential to the main goal</em>. </p>

<p>If you have a lot of chickens, you get a lot of eggs. OTOH, if you have a lot of eggs, you get a lot of chickens. Pigs, not so much. </p>

<p>However, if you are going to teach any given paradigm, you need to do it well. You need to make students completely comfortable in that paradigm so that when presented with a new problem they aren't confused about how to begin or what should be the next step. Languages/paradigms should fit like a comfortable pair of shoes. I'm not certain that current OOP education is as good as it could be, actually, but that is due to my own background. If we suddenly adopted FP widely, you might well think the same thing about the <em>then</em> state of the art concerning FP. Change happens, but it is slow and <em>is resisted</em>. </p>

<p>Students need two things at least. They need to be able to solve problems so that they can be successful in academia and/or the world of employment. But they also need to be able to <em>think</em> and be flexible so that they are able to move with the times as necessary. So we tend to teach one paradigm completely (for the first goal), but allow them exposure to others (for the second). Mostly it works. </p>

<hr>

<p>I'll also note that learning new languages is actually harder than it is often represented to be. If two languages are within one paradigm and have similar concepts then it may seem to be <em>merely</em> a question of new syntax applied to old ideas. Java and Python have similar ideas but quite different syntax. But learning the syntax of Python as an experienced Java programmer won't make you <em>pythonic.</em> But changing paradigms is much, much harder, even when the syntax is nearly the same. I'll note that C++ was derived from Dijkstra's ideas primarily (via Simula), whereas Java's core concepts come from Alan Kay. If you don't understand that then you can wind up programming badly in both languages. </p>

CC BY-SA 4.0
2018-05-14T17:20:25.010Z
Good points about the inertia and meeting expectations for entry-level positions.  I wonder if it still might be beneficial to teach both paradigms in introductory courses, so that when it comes to learning basic data-structures, like implementing a red-black tree, the student can implement the tree in a language like ML or Haskell, where inductive types are simply defined in a few lines of code, as opposed to implementing the tree in C or Java, where it would be much more verbose and the functionality of the tree would be obfuscated by the mechanics of the language.
Aaron M. Eshbach
CC BY-SA 4.0
2018-05-14T18:28:06.287Z
I think a bad idea. Students can wind up thrashing mentally. Paradigms, if they truly are are distinct. Their mental models can conflict. Give students a solid base in one before you try to teach them to "think different". Then you can be more clear about the advantages of each.
Buffy
CC BY-SA 4.0
2018-12-28T18:11:09.010Z
>>> I'll note that C++ was derived from Dijkstra's ideas primarily (via Simula), whereas Java's core concepts come from Alan Kay. 

Hm. Can you give an example?
paus
CC BY-SA 4.0
2018-12-28T18:13:40.697Z
@paus, I don't understand what you desire.  Stroustrup explicitly mentions Simula in his writings as a major influence. Java, like Smalltalk (inspired by Kay) is a class-based language with objects on the heap.
Buffy
CC BY-SA 4.0
2018-12-28T18:27:02.647Z
So, you mean the difficulty of understanding for high-level abstractions of programming, not choosing right programming language?
paus
CC BY-SA 4.0
2018-12-28T18:34:35.920Z
I think that most of the students have an experience like the following: "Once we tried to write something with our friends in the class on C++/Python/PHP, as hard as we could, and based on our experience we got it right". Although all my generation started from BASIC and Pascal, I don't think that they had an impact on the understanding of deeper principles, they only gave basic concepts. Other stuff we had to drink from industrial languages, not educational ones.
paus
CC BY-SA 4.0
2018-12-29T08:11:40.160Z
>>>  I'll note that C++ was derived from Dijkstra's ideas primarily (via Simula), whereas Java's core concepts come from Alan Kay. ---------- Nope. In Java there is no such OOP like in Smalltalk. There is an implementation like in Simula77/C++. In Ruby we have something like Kay's ideas - objects are trying to send messages to each other.
paus
CC BY-SA 4.0
2018-12-29T11:31:17.090Z
@paus, sorry, but you are wrong about Java. True that Ruby has a more pure implementation. But in Java, like smalltalk, objects are on the heap (not the stack) and are accessed via reference variables. And yes, objects send messages to one another. Java has a C-like substrate of non-objects but its objects are like those of Smalltalk, not those of Simula or C++. In C++ to get behavior like smalltalk (virtuality) you need to create an explicit pointer to an object (usually on the heap). You are missing something, I think.
Buffy
CC BY-SA 4.0
2018-12-30T12:11:05.830Z
@Buffy Java has the same table of methods like in C, and the search for the called method is done through it. Not like "I'm getting any message but for some responding 'I'm not able to do it'". Heap there or not - it's the detail of the runtime implementation. But how exactly the processing of messages is done - this is the implementation of the very principle of objectness and highly impact the idiomatics. And it's a huge gap between Java and SmallTalk, unlike Java and C, where the difference in the smartness of pointers. And Java has Simula-like OOP, with less poor implementation than in C++
paus
CC BY-SA 4.0
2018-12-30T13:35:37.587Z
@paus, Finally, I see the problem. You are, in essence, saying that since Java _variables_ have type that it is not "Smalltalk like". True that Smalltalk has untyped variables, but that isn't the central issue. The "table of methods" to which you refer, in Java only tells the runtime how to find a method, but _NOT what the method is_. The method itself is resolved at runtime through the object, not through the reference. It permits a more efficient runtime and earlier (compile time) error discovery. See: https://cseducators.stackexchange.com/a/5133/1293.
Buffy
CC BY-SA 4.0
2018-12-30T13:39:46.770Z
But having programmed in all of these languages, the mental model of programming in Java is the same as that of Ruby and very unlike that of C++ or Simula. Of course, the Ruby programmer need to take a bit more care that programs don't fail at runtime. But compile time method resolution is possible in Simula, and is not in Java. You cannot, in principle, know by reading a Java program which method will be executed except in those cases in which you know the most specific type of the object. That is what polymorphism gives you. There isn't "one" table of methods, there are several.
Buffy
CC BY-SA 4.0
2018-12-30T14:04:16.100Z
But Ruby still needs a way to do resolution. In this case, something like a hash map rather than a table will do the job. So the essential difference is whether an offset into a table (owned by the object) or a key into a map is used for resolution. That isn't really very different.
Buffy
CC BY-SA 4.0
2018-12-30T22:19:24.680Z
@Buffy polymorphism is available in C++ too. The gist is not to know which method is called. The gist is in how NOT to know. You are unconditionally sending messages to the object, which only decides how to react to them. There is no any other way to check whether the object responds or not to the message - only through sending an additional message like "describe what you are and what you can". In languages with the table of methods resolving is done by the compiler without any involvement of the object.  In Ruby, you can intercept the call of the method, what is Smalltalk-like in some sense.
paus
CC BY-SA 4.0
2018-12-30T22:27:58.113Z
@paus, yes, I know about C++. But you need to use an explicit pointer to object to achieve it. Let me repeat, the table used in Java only defines where the object can find the method. If you use the same code but it refers to different objects the table will be different as it is part of the object. The compiler can't resolve to the actual method. Only the object itself knows where its methods are and the object doesn't exist until runtime. And the reference to the object doesn't contain the most explicit type of the object. It is a runtime resolution, not compile time. You are missing that.
Buffy
CC BY-SA 4.0
2019-01-02T21:14:58.750Z
@Buffy In Smalltalk, the message is a string with names of the methods and names of the parameters. The object can forward it as a whole to another object, for example, and add a couple of parameters along the way. The closest analogy for that in C++ - RPC and other protobuf. I wrote the similar lib to connect independent parts of the program. In dynamically-typed languages, it's done by transferring the table, where keys are names of params. Objects are pointers in Java, they're only in heap.  The closest analogy in C++ - shared_ptr, but syntax overhead won't' make you happy.
paus
CC BY-SA 4.0
2019-01-02T21:34:17.417Z
@paus. This reads like a very naive view of how an interpreter might work. You seem to have some serious misconceptions about how languages are translated and executed.
Buffy
CC BY-SA 4.0
2019-01-02T21:42:40.580Z
@Buffy which one is "interpreter" among them? What exactly do you mean?
paus
CC BY-SA 4.0
2018-05-13T12:12:59.613Z
2018-05-13T12:34:13.117Z
2018-05-13T12:34:13.117Z
Buffy
<blockquote>
  <p>I found it strange when first learning Haskell that the language was never used in any of my classes, especially considering how much easier and more obvious it makes the implementation of fundamental data structures like trees and lists</p>
</blockquote>

<p>It might make implementing some data structures easier, but not all -- for example, I don't really think Haskell would make implementing arraylists or hashmaps necessarily easier.</p>

<p>(Also: I think implementing trees and lists is relatively simple in languages like Java or Python. The hard part, IMO, isn't teaching students how to implement trees or lists: the hard part is showing them how to manipulate them in arbitrary ways while avoiding edge cases. That's going to be challenging whether you approach the problem imperatively or functionally.)</p>

<blockquote>
  <p>When building enterprise-scale systems, avoiding things like state mutation becomes critical.</p>
</blockquote>

<p>But what if you want to implement something like a video game? Mutation is an integral part of programs like those. Of course, there are ways to restructure your code to avoid mutation, but most existing literature, tools, libraries, game engines, etc... related to gamedev don't take such an approach.</p>

<p>Or what if you want to go into embedded systems or security and end up needing to mess around with a lot of assembly or C? For better or for worse, you're going to end up spending a lot of time working with lower-level languages: functional languages won't necessarily end up being relevant to your work.</p>

<p>Or what if you're interested in scientific and mathematical computing? Again, I don't think functional languages are really widely-used here: languages like Python, R, Julia, C, or maybe even Matlab and Fortran are more ubiquitous for a variety of reasons.</p>

<p>Basically, a CS curriculum is supposed to prepare students to excel in a wide variety of backgrounds, not one specific area. For that reason, I don't know if it's necessarily correct to assume that all (or even most!) students will move into working on enterprise software and the like.</p>

<p>In particular, I think many "intro to CS" courses are targeted to be useful for people who may not necessarily want to move into computer science but still want to learn coding as a skill. In that case, you'd probably want to teach them a more mainstream language.</p>

<p>(You <em>could</em> also split up your "intro to CS" course into a "intro for non-majors" and "intro for majors", but that would introduce some overhead, both for students and teachers.)</p>

<hr>

<p>But of course, none of what I said above directly pertains to the heart of your question. I'm making the argument that a school shouldn't teach <em>only</em> functional programming, which isn't what you're asking: why don't we start with functional programming <em>first</em>?</p>

<p>Here, I'm personally not convinced that Haskell-style languages that push for immutability and clear containment of side-effects are actually going to be approachable, or even useful, for absolute beginners.</p>

<p>If somebody has zero background in programming and tech, one of the best ways of "hooking them in" is to have them start writing programs that actually do interesting things as soon as possible. That's why so many introductory tutorials these days start with webdev and JavaScript, why logo (and modules like 'turtle' in languages like Python) are such a popular choice, and so forth.</p>

<p>More recently, there's been a trend to start incorporating actual hardware into intro classes -- using things like <a href="http://microbit.org/" rel="noreferrer">micro:bits</a>, for example. Or to rephrase: a trend of finding ways of giving the student more interesting ways to mutate state: LEDs, stepper motors, electronic components, and so forth.</p>

<p>Contrast this with languages like Haskell: in order to do anything that interacts with the world, you need to start by explaining how the IO monad works (or find some convincing way of handwaving it all away).</p>

<p>While this isn't an insurmountable challenge, it <em>is</em> a potential stumbling block and is sort of annoying, especially if you're trying to ramp students up to doing interesting things as soon as possible. And the more you can improve potential stumbling blocks, the better. </p>

<p>A little more broadly, I think immutability and containment of side-effects can be very useful when working on large-scale programs, but they seem sort of gratuitous and unnecessary when working on smaller ones: it's challenging to demonstrate why they're useful, especially in intro when they have no context into what the alternative would look like.</p>

<p>(IMO this is also why many schools struggle with effectively teaching students how to use version control tools like git: even if you ask students to work in teams on a long-term project, you don't really need to use things like branches and can get away with just pushing directly to master.)</p>

<hr>

<p>Basically, while I'm a fan of functional programming, it's hard for me to see how exactly you'd go about teaching it to beginners. I'm sure that if I were really pressed, I could figure something out, but it's non-obvious to me how I'd teach the material in a high-quality way and how I'd rearrange certain topics I think are essential.</p>

<p>(For example, many students struggle immensely with the notion of "indirection" -- basically, how to use things like references and pointers. But if we're using an immutable language, indirection suddenly isn't as relevant: a variable could be a reference to some data or a copy of said data: it makes no difference. In that case, how and where should I teach students about indirection?)</p>

<p>Taking all of the above into account, I think a more tractable alternative is to start with a language like Python (or maybe Java?) <em>first</em>, then move on to more challenging languages like C or Haskell second.</p>

CC BY-SA 4.0
2018-09-05T12:46:07.263Z
"But what if you want to implement something like a video game? Mutation is an integral part of programs like those." – I believe that is a common misconception. "Super Monao Bros" is a Jump&Run Clone in Haskell. I once read an interesting blog series about Purely Functional Retrogames. Idris as a language is not only purely functional (no side-effects) but also total (always terminates, i.e. no endless recursion, no endless loops, and thus not Turing-complete), and one of the example programs is an Asteroids clone. [Note: technically speaking, Idris does not forbid writing non-terminating …
Jörg W Mittag
CC BY-SA 4.0
2018-09-05T12:46:33.223Z
… programs, it just makes no guarantees about type-safety if you do. This is unlike other dependently-typed languages, where you are not allowed to write non-terminating programs, and thus often have to jump through hoops to get the compiler to realize that your programs is actually terminating in all cases.]
Jörg W Mittag
CC BY-SA 4.0
2018-05-16T12:31:41.843Z
2018-05-16T12:31:41.843Z
Michael0x2a
<p>I have to thank you for helping me gain some insight on a very vexing question that I have always struggled with:  </p>

<blockquote>
  <p>Why are there so many companies making similar products?</p>
</blockquote>

<p>We see a big discrepancy in how things work: sometimes there is just one big player, which seems to have a "natural monopoly", something like Google, or Facebook. Not much point in having multiple Facebooks, right? So the also-rans don't run for long. This made me want to simply say that there should really be just one entrant in every field, and it should be the best. Put all your eggs in one basket, and make sure it is a <em>really strong</em> basket. Like, why so many car companies and models of cars? Just have one company, and a few models. Done. Instead, we have what we see: dozens of major car companies, all making oodles of very similar models and variations of products. Why on Earth do we do this?</p>

<p>A visit to the University library undid this idea, as I realized that people are creative and all want to make a mark on the world. Books, paintings, music I can understand. But <em>cars</em>? Who gives a rip? So I realized that there are things that are salient to people and things that are not, and this varies individually. I don't care about cars, but don't try to pry my favorite music or brand of coffee away from me. (But why don't people just choose the <em>obviously best</em> kind of coffee and music?) (Shh! you'll ruin the story)</p>

<p>Back to your question: people do not use functional programming because <strong>that is not how they think</strong>. If you go to a hardware store, you do not see motors and bearings, gear-sets and belts and reciprocators. You see angle grinders, drill presses, belt sanders, lathes... In other words, you see special purpose tools, not general purpose components. The home store has cabinets, washing machines and toilets, not wood, metal and ceramic. People want to get the thing that they are thinking of, not think about how to fabricate it. And they want tools that take them directly to that objective. Radio Shack stores are slowly closing, because few people have any interest in building electronic things that they can much more easily and cheaply buy. I don't know many other people who have built a shortwave receiver from random used parts in a box, or contacting someone thousands of miles away using a few watts of power and Morse code. And they are not in the least interested in doing so! Stunning.</p>

<p>I actually learned Lisp in college before C, but I have never used Lisp professionally. Most people are not going to construct a programming system from the ground up, they start with something high-level that is close to their desired outcome, and they snap parts together, or use high-level tools (like IDEs and visual design products) to achieve it. It is great that one can use the vi editor to create a spreadsheet (TeX) or a complex document (TROFF) or an AI program (by writing Lisp) or an operating system (by writing C), but Unix is still not a large share of the computing market (just in the areas where it matters) and even Apple is not dominant, because computing is mostly a matter of managing money (Windows and its products). It is a lot easier to write an ebook using Word than whatever the alternative is, which I never looked into because I learned Word decades ago. I learned it because it could do all the things I needed to, and it still does.</p>

<p>Some people would rather teach you how to build a watch than simply tell you what time it is, and it is true that if you teach a man to fish he can eat for a lifetime. But there are still a lot more people out there buying watches and going to restaurants, because they have other things on their minds than how to write complex computer programs. Even if they are programmers. So, "the industry" that you referred to, is really many industries, not just the academic view of "real computing".</p>

<p>So, thanks for prompting me to think this through in a general way so that I can write another very specific chapter in my next book, coalescing years of rumination, frustration and exasperation and hopefully creating some enlightenment out of it.</p>

CC BY-SA 4.0
2018-05-14T16:24:15.340Z
I see two errors here. People can think functionally just as they can procedurally. It just takes education and practice. And practice. It is a different way of thinking but accessible to all. Secondly, functional programmers in Lisp or Haskel (other choices...) don't, in fact, build everything from scratch. There are sophisticated libraries for functional languages just as for the others. CLOS for Common Lisp is one example. In fact, the ability to do meta programming in functional languages, just becoming possible in Java, permits very powerful constructs to be built and leveraged.
Buffy
CC BY-SA 4.0
2018-05-14T16:29:46.023Z
I have to agree with Buffy, the toolchains for FP are just as, if not more sophisticated, than the ones for imperative programming.  In fact, because of the ease of, i.e. composing monads or using higher-kinded types, you often have to do a lot less of the grunt-work yourself in FP than in OOP.
Aaron M. Eshbach
CC BY-SA 4.0
2018-05-14T19:39:34.863Z
See, for example: https://www.amazon.com/Art-Metaobject-Protocol-Gregor-Kiczales/dp/0262610744/. If you want to make someone very happy, buy the hardcover. Hmmm. I actually have one of those.
Buffy
CC BY-SA 4.0
2018-05-14T19:44:30.363Z
Also see various writings by Paul Graham. e.g. Hackers and Painters. Here is his blog: http://paulgraham.com/articles.html.
Buffy
CC BY-SA 4.0
2018-08-01T02:01:20.510Z
I don't think the reason FP isn't taught has anything to do with composability. It's just inertia. And *maybe* also related to the way incoming students already think.
Criticize SE actions means ban
CC BY-SA 4.0
2018-05-14T15:15:36.857Z
2018-05-14T15:15:36.857Z
user5186
<p>First of all, I question somewhat the premise of your query; there are many programs that <em>do</em> teach functional programming first.</p>

<p>That said, there are both historical and practical reasons for an emphasis on imperative programming.  The Von Neumann architecture was modeled after the Turing machine, not after the lambda calculus. State change and mutability have been baked into electronic computers for as long as we have had electronic computers. </p>

<p>Our stateless languages are abstractions built atop the descendants of the Von Neumann architecture, not the other way, and the compiled code from Haskell and the like all utilize memory mutation. If we take it as a given that one of the goals of a CS program is to give a sense of how our computers work at a low level, functional programming does not advance this goal.</p>

<p>That's not to say that functional programming is not without value; I also teach it (as a second language), but curricular hours are not infinite, and I know from experience that all of the concepts that get jettisoned are each precious, irreplaceable rubies in their own right.  When designing a four-year curriculum, you are faced with very hard choices.</p>

<p>It's also important to note (and this has has been discussed many times across this site) that mutability is not always easy for students to wrap their brain around, and often takes some serious time to sink in. For many students, this idea seems very natural, but there is always a significant group who gets stuck here. Not adressing mutability directly will make it very hard for a certain subset of students to pick up imperative languages on their own later.  The idea that this can be hard is itself hard to understand for those who understood it naturally, but imagine that you are graduating students who can recurse, but get a little fuzzy when trying to follow</p>

<pre><code>if(x == 7){
   x++;
}
if (x == 7) {
   x--;
}
</code></pre>

<p>Historically speaking, Fortran was more successful than LISP, and C was more successful than Scheme.  Imperative languages resemble the machines they are built upon, and it's only natural, then, that schools in earlier days would have found it important to focus on Turing, Von Neumann, assembly, C, and the like.</p>

<p>Haskell is still trying to prove that it can compile efficiently.  Meanwhile, it's only in the last ten years that lambdas have come to wide acceptance in industry.  It makes sense, then, for both historical and continuity reasons, that schools have focused more on imperative languages.</p>

CC BY-SA 4.0
2018-05-15T12:04:52.323Z
With modern hardware, the way the system actually works is so different from traditional understanding, that I think it's actually counterproductive to think about it.  From superscalar architectures to branch prediction and multi-core platforms, the way a CPU works internally is now very complex.  I think it's better to let the computer engineers think about how the hardware will work and have computer scientists focus on writing well-designed, maintainable software, especially given the increasingly platform-independent nature of software development.
Aaron M. Eshbach
CC BY-SA 4.0
2018-05-15T12:13:06.170Z
This blog by Raymond Chen (a C developer working on the Windows OS at Microsoft) is informative:  https://blogs.msdn.microsoft.com/oldnewthing/20140613-00/?p=743.  The branch predictor will completely change the expected execution of your code anyway, so best just not to try to anticipate the hardware behavior and focus on the quality of the software.
Aaron M. Eshbach
CC BY-SA 4.0
2018-05-15T13:09:25.550Z
@AaronM.Eshbach You mean the Software Engineers? Computer Scientists shouldn't be particularly focused on writing software well-designed, maintainable software unless that is their area of focus/research. Computer Scientists *should* be focused pretty squarely on understanding complex interactions, algorithms, and computation. Branch prediction and superscalar architectures are great areas of modern interplay between CS and engineering.
Ben I.
CC BY-SA 4.0
2018-05-15T13:13:58.293Z
Perhaps Software Engineering would be the more appropriate discipline.  There wasn't really a Software Engineering major when I attended university, so I don't know what that covers.  At the school I attended, Computer Engineers took a blend of hardware and software courses (including Digital Design and working with FPGAs, etc.) while Computer Scientists took almost entirely software courses, with some basic education on K-maps and the like.
Aaron M. Eshbach
CC BY-SA 4.0
2018-05-15T13:19:10.053Z
@AaronM.Eshbach Yeah, my major was not dissimilar. But things seem to be improving on this front. More schools are offering legitimate SE degrees, which really has blossomed into its own distinct field. I'm hopeful that this shift should be freeing CS majors to spend more time engaging in theory.
Ben I.
CC BY-SA 4.0
2018-05-14T20:53:55.947Z
2018-05-14T20:53:55.947Z
Ben I.
<p>The computing ecosystem keeps making smaller and smaller things.  Imperative programming is far better matched to Arduinos and other small cheap computers that a k12 and earlier student is likely to tinker with (as opposed to just be a user of).</p>

CC BY-SA 4.0
2018-05-17T20:14:43.093Z
Today's tiny Arduino is much larger than the big computer we had here when I was a student... even my old cellphone has more oomph.
vonbrand
CC BY-SA 4.0
2018-05-17T23:11:00.237Z
Might be an interesting project to replace Wiring with a Lisp/Scheme derivative.  Anyone done that yet?  Will it fit any Atmel AVR?
hotpaw2
CC BY-SA 4.0
2018-05-18T13:03:27.647Z
I've got Maxima (a largeish Common Lisp program) running on my cellphone. It is far from the largest application there...
vonbrand
CC BY-SA 4.0
2018-05-18T14:59:34.033Z
Contemporary mobile phones have more compute+memory than not-to-distant supercomputers (Cray YMP, et.al.).  Whereas an Arduino chip might have only 2k of RAM.
hotpaw2
CC BY-SA 4.0
2019-05-03T21:52:39.870Z
Added: I would not be surprised if a lack of appreciation for the disadvantages of functional programming might be a significant contribution to increasing global CO2 emissions, due to inefficient use of vast amounts of data center hardware.
hotpaw2
CC BY-SA 4.0
2018-05-16T19:36:50.220Z
2018-05-16T19:36:50.220Z
hotpaw2
<p>It is just that we <em>think</em> procedurally. We "go to the store", we "cook dinner", we "do the dishes", and so on. The functional, recursive, based on induction, mathematical, thinking is very far from natural (ask any teacher of mathematics to students in first-year calculus courses, take a peek at what the colleagues of the math department think about their freshmen). Sure, programming is (thinly disguised) math, and so math style (functional programming) is more "natural" <em>if you have groked math</em>. Most people never get it.</p>

CC BY-SA 4.0
2018-05-18T12:38:13.267Z
I'm not sure your examples illustrate a difference between functional and imperative programming.  Your verb-phrases would all be function names, the only difference is that in FP, instead of mutating the state of "my location", "dinner", and "the dishes", the functions would return the "my new location", "the cooked dinner", and "the washed dishes".  If you wanted to do those things in order and pass the groceries we bought at the store into "cook dinner" and the dishes from dinner into "do the dishes", we just use composition.
Aaron M. Eshbach
CC BY-SA 4.0
2018-05-18T13:01:31.833Z
@AaronM.Eshbach, you *can* model it that way, but it is a world away from how you naturally *think* about it. "I have a bunch of functions that input a whole world and spit out another" isn't the way we think, we think of changing an tiny corner of a (mostly unchanging, totally irrelevant) world, one step at a time.
vonbrand
CC BY-SA 4.0
2019-04-24T11:23:29.947Z
You could say that most of the world around us might as well be a vast collection of global constants and methods that we either are not aware of at all or at least not allowed to run. Finding something that actually *responds* is probably most of a baby's first 2 years of existence. So Procedural makes sense in that way. And, we don't just line up grocery shopping, cooking and washing dishes and push one button and walk away with a full belly and clean new kitchen, we have to push and pull every object and verify that every dish is clean. Not to mention biting the inside of your mouth (bug).
Scott Rowe
CC BY-SA 4.0
2019-10-06T19:06:15.413Z
It always seems not good to me when assertions are made about "we" as in all humans; evidence suggests that for any imaginable feature differing options exist. The correspondence between sequential thoughts and state transitions holds only at a very initial level and I believe it's the root of the difficulty so many students meet. Furthermore speaking simply from *my* point of view what you say is not true, I think functionally. In my very first moments with programming I was surprised that C did not behave like Haskell, which I didn't know: I would have appreciated to be shown it existed.
user9137
CC BY-SA 4.0
2018-05-18T12:28:44.357Z
2018-05-18T12:28:44.357Z
vonbrand
<p>We've recently gone through the process of selecting an intern from a local university to join our team for the summer.  We are using F# and almost exclusively using functional programming techniques on our team, and finding a candidate with any exposure to functional programming proved to be impossible.  This isn't that surprising, given that even several senior members of the team with Master's degrees didn't have much exposure to functional programming before joining our team.  However, I've been wondering why so few undergraduate programs teach functional programming concepts.</p>

<p>Having attended a university that taught C/C++/Java for 90% of my undergraduate classes, I found it strange when first learning Haskell that the language was never used in any of my classes, especially considering how much easier and more obvious it makes the implementation of fundamental data structures like trees and lists.  When building enterprise-scale systems, avoiding things like state mutation becomes critical.  So why aren't functional languages taught first, and functional programming techniques taught as a "use this approach first, when possible" with imperative techniques and things like explicit memory management and use of mutable state taught as "only use this when absolutely necessary for performance reasons"?</p>

<p>I would think, with the increasing move towards multi-core processors, and the growing relevance of distributed systems, that teaching functional programming from the beginning would be the best way to prepare students for successful careers in the industry.  Is there a reason that universities avoid teaching Haskell or other functional languages first (or at least including them as a major part of the undergraduate curriculum) and teaching imperative programming as a supplementary skillset?</p>

CC BY-SA 4.0
2018-05-12T23:49:22.320Z
Welcome to CSEducators. You seem to be simply asking for opinions, rather than how to teach. We try to put more emphasis here on how to do things. Maybe the situation about FP will change.
Buffy
CC BY-SA 4.0
2018-05-12T23:50:28.693Z
Thanks, can you suggest a better place for this type of question?
Aaron M. Eshbach
CC BY-SA 4.0
2018-05-12T23:52:04.053Z
The ACM SIGCSE mailing list might be a start. Membership required, though.
Buffy
CC BY-SA 4.0
2018-05-13T00:59:56.553Z
Part of the problem is probably based on employ-ability. Wages might be higher in functional programming positions, but a high wage only applies when there is a job to be had. Check out the current SO [Developer Survey results](https://insights.stackoverflow.com/survey/2018/#technology-programming-scripting-and-markup-languages)
Gypsy Spellweaver
CC BY-SA 4.0
2018-05-13T02:15:15.557Z
I don't really think employ-ability would be affected.  Learning FP first would make you better at any language, because you would more instinctively avoid shared mutable state, better encapsulate effects in the type system, etc.  Also, few people end up working exclusively in the languages they learned in school.  Learning new languages on the fly is par for the course in a programming job.  This is more about what fundamental techniques are the right ones to learn first.
Aaron M. Eshbach
CC BY-SA 4.0
2018-05-13T03:57:16.237Z
It's probably because functional programming is still an esoteric skill, so there are a limited number of people who can do and teach it well.
pojo-guy
CC BY-SA 4.0
2018-05-13T18:58:24.213Z
We should note this related question: https://cseducators.stackexchange.com/q/3558/1293
Buffy
<curriculum-design><undergraduate><functional-programming>
Why isn't Functional Programming Taught First?
# Why isn't Functional Programming Taught First?

(Asked by: username_0 on 2018-05-12)

We've recently gone through the process of selecting an intern from a local university to join our team for the summer. We are using F# and almost exclusively using functional programming techniques on our team, and finding a candidate with any exposure to functional programming proved to be impossible. This isn't that surprising, given that even several senior members of the team with Master's degrees didn't have much exposure to functional programming before joining our team. However, I've been wondering why so few undergraduate programs teach functional programming concepts.

Having attended a university that taught C/C++/Java for 90% of my undergraduate classes, I found it strange when first learning Haskell that the language was never used in any of my classes, especially considering how much easier and more obvious it makes the implementation of fundamental data structures like trees and lists. When building enterprise-scale systems, avoiding things like state mutation becomes critical. So why aren't functional languages taught first, and functional programming techniques taught as a "use this approach first, when possible" with imperative techniques and things like explicit memory management and use of mutable state taught as "only use this when absolutely necessary for performance reasons"?

I would think, with the increasing move towards multi-core processors, and the growing relevance of distributed systems, that teaching functional programming from the beginning would be the best way to prepare students for successful careers in the industry. Is there a reason that universities avoid teaching Haskell or other functional languages first (or at least including them as a major part of the undergraduate curriculum) and teaching imperative programming as a supplementary skillset?

**Tags:** curriculum-design, undergraduate, functional-programming

> **Comments:**
> **username_1**: Welcome to CSEducators. You seem to be simply asking for opinions, rather than how to teach. We try to put more emphasis here on how to do things. Maybe the situation about FP will change.  
> **username_0**: Thanks, can you suggest a better place for this type of question?  
> **username_1**: The ACM SIGCSE mailing list might be a start. Membership required, though.  
> **username_2**: Part of the problem is probably based on employ-ability. Wages might be higher in functional programming positions, but a high wage only applies when there is a job to be had. Check out the current SO [Developer Survey results](https://insights.stackoverflow.com/survey/2018/#technology-programming-scripting-and-markup-languages)  
> **username_0**: I don't really think employ-ability would be affected.  Learning FP first would make you better at any language, because you would more instinctively avoid shared mutable state, better encapsulate effects in the type system, etc.  Also, few people end up working exclusively in the languages they learned in school.  Learning new languages on the fly is par for the course in a programming job.  This is more about what fundamental techniques are the right ones to learn first.  
> **username_3**: It's probably because functional programming is still an esoteric skill, so there are a limited number of people who can do and teach it well.  
> **username_1**: We should note this related question: https://cseducators.stackexchange.com/q/3558/1293  

---

## 6 answers

### Answer by username_1 on 2018-05-13. Score: 8 | Accepted answer

The *why* isn't necessarily related to the relative quality or benefit of the various approaches to the first courses. But some of the comments given to the question capture part of the reasons.

First, FP isn't precisely mainstream in industry. Most programming in the real world is *now* is done in Dijkstra-derived languages, not McCarthy-derived ones. This may change, of course, as the world starts to recognize the benefits of FP as it previously did for OOP. As the questioner mentioned FP has advantages in some important areas. But most curricula take a look at who is hiring entry level folks and what they want to see in the person's background.

Another reason is that most of the faculty is much more knowledgeable about those *mainstream* things than others. If the faculty went through a long program in which almost everything is built in Dijkstra-derived languages that is what they are more likely to teach beginners. OTOH, faculty (including some folks here) who went to, just to pick a name, MIT, are more likely to start in FP, but may still be constrained by the first reason.

Most faculty still think of FP as an advanced topic and so Let and Lambda tend to come late in the curriculum, after the students have *seasoning*. As you suggest this is not necessary, and may not be desirable, but there is a lot of inertia.

There is always some mental disruption when a student is asked to change paradigms, since a paradigm is built on a consistent mental model that is also relatively *closed*, not needing outside explanations. Paradigm shift is, in general, difficult, even for experts. The HS or undergraduate curriculum is short in time so most faculty are resistant, at least a bit, to require uproar in the middle of the two or four years. Much better, it is normally thought, to treat one paradigm as the main-line and any others as *nice but inessential to the main goal*.

If you have a lot of chickens, you get a lot of eggs. OTOH, if you have a lot of eggs, you get a lot of chickens. Pigs, not so much.

However, if you are going to teach any given paradigm, you need to do it well. You need to make students completely comfortable in that paradigm so that when presented with a new problem they aren't confused about how to begin or what should be the next step. Languages/paradigms should fit like a comfortable pair of shoes. I'm not certain that current OOP education is as good as it could be, actually, but that is due to my own background. If we suddenly adopted FP widely, you might well think the same thing about the *then* state of the art concerning FP. Change happens, but it is slow and *is resisted*.

Students need two things at least. They need to be able to solve problems so that they can be successful in academia and/or the world of employment. But they also need to be able to *think* and be flexible so that they are able to move with the times as necessary. So we tend to teach one paradigm completely (for the first goal), but allow them exposure to others (for the second). Mostly it works.

---

I'll also note that learning new languages is actually harder than it is often represented to be. If two languages are within one paradigm and have similar concepts then it may seem to be *merely* a question of new syntax applied to old ideas. Java and Python have similar ideas but quite different syntax. But learning the syntax of Python as an experienced Java programmer won't make you *pythonic.* But changing paradigms is much, much harder, even when the syntax is nearly the same. I'll note that C++ was derived from Dijkstra's ideas primarily (via Simula), whereas Java's core concepts come from Alan Kay. If you don't understand that then you can wind up programming badly in both languages.

> **Comments:**
> **username_0**: Good points about the inertia and meeting expectations for entry-level positions.  I wonder if it still might be beneficial to teach both paradigms in introductory courses, so that when it comes to learning basic data-structures, like implementing a red-black tree, the student can implement the tree in a language like ML or Haskell, where inductive types are simply defined in a few lines of code, as opposed to implementing the tree in C or Java, where it would be much more verbose and the functionality of the tree would be obfuscated by the mechanics of the language.  
> **username_1**: I think a bad idea. Students can wind up thrashing mentally. Paradigms, if they truly are are distinct. Their mental models can conflict. Give students a solid base in one before you try to teach them to "think different". Then you can be more clear about the advantages of each.  
> **username_4**: >>> I'll note that C++ was derived from Dijkstra's ideas primarily (via Simula), whereas Java's core concepts come from Alan Kay.   Hm. Can you give an example?  
> **username_1**: @username_4, I don't understand what you desire.  Stroustrup explicitly mentions Simula in his writings as a major influence. Java, like Smalltalk (inspired by Kay) is a class-based language with objects on the heap.  
> **username_4**: So, you mean the difficulty of understanding for high-level abstractions of programming, not choosing right programming language?  
> **username_4**: I think that most of the students have an experience like the following: "Once we tried to write something with our friends in the class on C++/Python/PHP, as hard as we could, and based on our experience we got it right". Although all my generation started from BASIC and Pascal, I don't think that they had an impact on the understanding of deeper principles, they only gave basic concepts. Other stuff we had to drink from industrial languages, not educational ones.  
> **username_4**: >>>  I'll note that C++ was derived from Dijkstra's ideas primarily (via Simula), whereas Java's core concepts come from Alan Kay. ---------- Nope. In Java there is no such OOP like in Smalltalk. There is an implementation like in Simula77/C++. In Ruby we have something like Kay's ideas - objects are trying to send messages to each other.  
> **username_1**: @username_4, sorry, but you are wrong about Java. True that Ruby has a more pure implementation. But in Java, like smalltalk, objects are on the heap (not the stack) and are accessed via reference variables. And yes, objects send messages to one another. Java has a C-like substrate of non-objects but its objects are like those of Smalltalk, not those of Simula or C++. In C++ to get behavior like smalltalk (virtuality) you need to create an explicit pointer to an object (usually on the heap). You are missing something, I think.  
> **username_4**: @username_1 Java has the same table of methods like in C, and the search for the called method is done through it. Not like "I'm getting any message but for some responding 'I'm not able to do it'". Heap there or not - it's the detail of the runtime implementation. But how exactly the processing of messages is done - this is the implementation of the very principle of objectness and highly impact the idiomatics. And it's a huge gap between Java and SmallTalk, unlike Java and C, where the difference in the smartness of pointers. And Java has Simula-like OOP, with less poor implementation than in C++  
> **username_1**: @username_4, Finally, I see the problem. You are, in essence, saying that since Java _variables_ have type that it is not "Smalltalk like". True that Smalltalk has untyped variables, but that isn't the central issue. The "table of methods" to which you refer, in Java only tells the runtime how to find a method, but _NOT what the method is_. The method itself is resolved at runtime through the object, not through the reference. It permits a more efficient runtime and earlier (compile time) error discovery. See: https://cseducators.stackexchange.com/a/5133/1293.  
> **username_1**: But having programmed in all of these languages, the mental model of programming in Java is the same as that of Ruby and very unlike that of C++ or Simula. Of course, the Ruby programmer need to take a bit more care that programs don't fail at runtime. But compile time method resolution is possible in Simula, and is not in Java. You cannot, in principle, know by reading a Java program which method will be executed except in those cases in which you know the most specific type of the object. That is what polymorphism gives you. There isn't "one" table of methods, there are several.  
> **username_1**: But Ruby still needs a way to do resolution. In this case, something like a hash map rather than a table will do the job. So the essential difference is whether an offset into a table (owned by the object) or a key into a map is used for resolution. That isn't really very different.  
> **username_4**: @username_1 polymorphism is available in C++ too. The gist is not to know which method is called. The gist is in how NOT to know. You are unconditionally sending messages to the object, which only decides how to react to them. There is no any other way to check whether the object responds or not to the message - only through sending an additional message like "describe what you are and what you can". In languages with the table of methods resolving is done by the compiler without any involvement of the object.  In Ruby, you can intercept the call of the method, what is Smalltalk-like in some sense.  
> **username_1**: @username_4, yes, I know about C++. But you need to use an explicit pointer to object to achieve it. Let me repeat, the table used in Java only defines where the object can find the method. If you use the same code but it refers to different objects the table will be different as it is part of the object. The compiler can't resolve to the actual method. Only the object itself knows where its methods are and the object doesn't exist until runtime. And the reference to the object doesn't contain the most explicit type of the object. It is a runtime resolution, not compile time. You are missing that.  
> **username_4**: @username_1 In Smalltalk, the message is a string with names of the methods and names of the parameters. The object can forward it as a whole to another object, for example, and add a couple of parameters along the way. The closest analogy for that in C++ - RPC and other protobuf. I wrote the similar lib to connect independent parts of the program. In dynamically-typed languages, it's done by transferring the table, where keys are names of params. Objects are pointers in Java, they're only in heap.  The closest analogy in C++ - shared_ptr, but syntax overhead won't' make you happy.  
> **username_1**: @username_4. This reads like a very naive view of how an interpreter might work. You seem to have some serious misconceptions about how languages are translated and executed.  
> **username_4**: @username_1 which one is "interpreter" among them? What exactly do you mean?  

---

### Answer by username_5 on 2018-05-16. Score: 5

> I found it strange when first learning Haskell that the language was never used in any of my classes, especially considering how much easier and more obvious it makes the implementation of fundamental data structures like trees and lists

It might make implementing some data structures easier, but not all -- for example, I don't really think Haskell would make implementing arraylists or hashmaps necessarily easier.

(Also: I think implementing trees and lists is relatively simple in languages like Java or Python. The hard part, IMO, isn't teaching students how to implement trees or lists: the hard part is showing them how to manipulate them in arbitrary ways while avoiding edge cases. That's going to be challenging whether you approach the problem imperatively or functionally.)

> When building enterprise-scale systems, avoiding things like state mutation becomes critical.

But what if you want to implement something like a video game? Mutation is an integral part of programs like those. Of course, there are ways to restructure your code to avoid mutation, but most existing literature, tools, libraries, game engines, etc... related to gamedev don't take such an approach.

Or what if you want to go into embedded systems or security and end up needing to mess around with a lot of assembly or C? For better or for worse, you're going to end up spending a lot of time working with lower-level languages: functional languages won't necessarily end up being relevant to your work.

Or what if you're interested in scientific and mathematical computing? Again, I don't think functional languages are really widely-used here: languages like Python, R, Julia, C, or maybe even Matlab and Fortran are more ubiquitous for a variety of reasons.

Basically, a CS curriculum is supposed to prepare students to excel in a wide variety of backgrounds, not one specific area. For that reason, I don't know if it's necessarily correct to assume that all (or even most!) students will move into working on enterprise software and the like.

In particular, I think many "intro to CS" courses are targeted to be useful for people who may not necessarily want to move into computer science but still want to learn coding as a skill. In that case, you'd probably want to teach them a more mainstream language.

(You *could* also split up your "intro to CS" course into a "intro for non-majors" and "intro for majors", but that would introduce some overhead, both for students and teachers.)

---

But of course, none of what I said above directly pertains to the heart of your question. I'm making the argument that a school shouldn't teach *only* functional programming, which isn't what you're asking: why don't we start with functional programming *first*?

Here, I'm personally not convinced that Haskell-style languages that push for immutability and clear containment of side-effects are actually going to be approachable, or even useful, for absolute beginners.

If somebody has zero background in programming and tech, one of the best ways of "hooking them in" is to have them start writing programs that actually do interesting things as soon as possible. That's why so many introductory tutorials these days start with webdev and JavaScript, why logo (and modules like 'turtle' in languages like Python) are such a popular choice, and so forth.

More recently, there's been a trend to start incorporating actual hardware into intro classes -- using things like [micro:bits](http://microbit.org/), for example. Or to rephrase: a trend of finding ways of giving the student more interesting ways to mutate state: LEDs, stepper motors, electronic components, and so forth.

Contrast this with languages like Haskell: in order to do anything that interacts with the world, you need to start by explaining how the IO monad works (or find some convincing way of handwaving it all away).

While this isn't an insurmountable challenge, it *is* a potential stumbling block and is sort of annoying, especially if you're trying to ramp students up to doing interesting things as soon as possible. And the more you can improve potential stumbling blocks, the better.

A little more broadly, I think immutability and containment of side-effects can be very useful when working on large-scale programs, but they seem sort of gratuitous and unnecessary when working on smaller ones: it's challenging to demonstrate why they're useful, especially in intro when they have no context into what the alternative would look like.

(IMO this is also why many schools struggle with effectively teaching students how to use version control tools like git: even if you ask students to work in teams on a long-term project, you don't really need to use things like branches and can get away with just pushing directly to master.)

---

Basically, while I'm a fan of functional programming, it's hard for me to see how exactly you'd go about teaching it to beginners. I'm sure that if I were really pressed, I could figure something out, but it's non-obvious to me how I'd teach the material in a high-quality way and how I'd rearrange certain topics I think are essential.

(For example, many students struggle immensely with the notion of "indirection" -- basically, how to use things like references and pointers. But if we're using an immutable language, indirection suddenly isn't as relevant: a variable could be a reference to some data or a copy of said data: it makes no difference. In that case, how and where should I teach students about indirection?)

Taking all of the above into account, I think a more tractable alternative is to start with a language like Python (or maybe Java?) *first*, then move on to more challenging languages like C or Haskell second.

> **Comments:**
> **username_6**: "But what if you want to implement something like a video game? Mutation is an integral part of programs like those." – I believe that is a common misconception. "Super Monao Bros" is a Jump&Run Clone in Haskell. I once read an interesting blog series about Purely Functional Retrogames. Idris as a language is not only purely functional (no side-effects) but also total (always terminates, i.e. no endless recursion, no endless loops, and thus not Turing-complete), and one of the example programs is an Asteroids clone. [Note: technically speaking, Idris does not forbid writing non-terminating …  
> **username_6**: … programs, it just makes no guarantees about type-safety if you do. This is unlike other dependently-typed languages, where you are not allowed to write non-terminating programs, and thus often have to jump through hoops to get the compiler to realize that your programs is actually terminating in all cases.]  

---

### Answer by username_7 on 2018-05-14. Score: 3

I have to thank you for helping me gain some insight on a very vexing question that I have always struggled with:

> Why are there so many companies making similar products?

We see a big discrepancy in how things work: sometimes there is just one big player, which seems to have a "natural monopoly", something like Google, or Facebook. Not much point in having multiple Facebooks, right? So the also-rans don't run for long. This made me want to simply say that there should really be just one entrant in every field, and it should be the best. Put all your eggs in one basket, and make sure it is a *really strong* basket. Like, why so many car companies and models of cars? Just have one company, and a few models. Done. Instead, we have what we see: dozens of major car companies, all making oodles of very similar models and variations of products. Why on Earth do we do this?

A visit to the University library undid this idea, as I realized that people are creative and all want to make a mark on the world. Books, paintings, music I can understand. But *cars*? Who gives a rip? So I realized that there are things that are salient to people and things that are not, and this varies individually. I don't care about cars, but don't try to pry my favorite music or brand of coffee away from me. (But why don't people just choose the *obviously best* kind of coffee and music?) (Shh! you'll ruin the story)

Back to your question: people do not use functional programming because **that is not how they think**. If you go to a hardware store, you do not see motors and bearings, gear-sets and belts and reciprocators. You see angle grinders, drill presses, belt sanders, lathes... In other words, you see special purpose tools, not general purpose components. The home store has cabinets, washing machines and toilets, not wood, metal and ceramic. People want to get the thing that they are thinking of, not think about how to fabricate it. And they want tools that take them directly to that objective. Radio Shack stores are slowly closing, because few people have any interest in building electronic things that they can much more easily and cheaply buy. I don't know many other people who have built a shortwave receiver from random used parts in a box, or contacting someone thousands of miles away using a few watts of power and Morse code. And they are not in the least interested in doing so! Stunning.

I actually learned Lisp in college before C, but I have never used Lisp professionally. Most people are not going to construct a programming system from the ground up, they start with something high-level that is close to their desired outcome, and they snap parts together, or use high-level tools (like IDEs and visual design products) to achieve it. It is great that one can use the vi editor to create a spreadsheet (TeX) or a complex document (TROFF) or an AI program (by writing Lisp) or an operating system (by writing C), but Unix is still not a large share of the computing market (just in the areas where it matters) and even Apple is not dominant, because computing is mostly a matter of managing money (Windows and its products). It is a lot easier to write an ebook using Word than whatever the alternative is, which I never looked into because I learned Word decades ago. I learned it because it could do all the things I needed to, and it still does.

Some people would rather teach you how to build a watch than simply tell you what time it is, and it is true that if you teach a man to fish he can eat for a lifetime. But there are still a lot more people out there buying watches and going to restaurants, because they have other things on their minds than how to write complex computer programs. Even if they are programmers. So, "the industry" that you referred to, is really many industries, not just the academic view of "real computing".

So, thanks for prompting me to think this through in a general way so that I can write another very specific chapter in my next book, coalescing years of rumination, frustration and exasperation and hopefully creating some enlightenment out of it.

> **Comments:**
> **username_1**: I see two errors here. People can think functionally just as they can procedurally. It just takes education and practice. And practice. It is a different way of thinking but accessible to all. Secondly, functional programmers in Lisp or Haskel (other choices...) don't, in fact, build everything from scratch. There are sophisticated libraries for functional languages just as for the others. CLOS for Common Lisp is one example. In fact, the ability to do meta programming in functional languages, just becoming possible in Java, permits very powerful constructs to be built and leveraged.  
> **username_0**: I have to agree with username_1, the toolchains for FP are just as, if not more sophisticated, than the ones for imperative programming.  In fact, because of the ease of, i.e. composing monads or using higher-kinded types, you often have to do a lot less of the grunt-work yourself in FP than in OOP.  
> **username_1**: See, for example: https://www.amazon.com/Art-Metaobject-Protocol-Gregor-Kiczales/dp/0262610744/. If you want to make someone very happy, buy the hardcover. Hmmm. I actually have one of those.  
> **username_1**: Also see various writings by Paul Graham. e.g. Hackers and Painters. Here is his blog: http://paulgraham.com/articles.html.  
> **username_8**: I don't think the reason FP isn't taught has anything to do with composability. It's just inertia. And *maybe* also related to the way incoming students already think.  

---

### Answer by username_9 on 2018-05-14. Score: 2

First of all, I question somewhat the premise of your query; there are many programs that do teach functional programming first.
That said, there are both historical and practical reasons for an emphasis on imperative programming.  The Von Neumann architecture was modeled after the Turing machine, not after the lambda calculus. State change and mutability have been baked into electronic computers for as long as we have had electronic computers. 
Our stateless languages are abstractions built atop the descendants of the Von Neumann architecture, not the other way, and the compiled code from Haskell and the like all utilize memory mutation. If we take it as a given that one of the goals of a CS program is to give a sense of how our computers work at a low level, functional programming does not advance this goal.
That's not to say that functional programming is not without value; I also teach it (as a second language), but curricular hours are not infinite, and I know from experience that all of the concepts that get jettisoned are each precious, irreplaceable rubies in their own right.  When designing a four-year curriculum, you are faced with very hard choices.
It's also important to note (and this has has been discussed many times across this site) that mutability is not always easy for students to wrap their brain around, and often takes some serious time to sink in. For many students, this idea seems very natural, but there is always a significant group who gets stuck here. Not adressing mutability directly will make it very hard for a certain subset of students to pick up imperative languages on their own later.  The idea that this can be hard is itself hard to understand for those who understood it naturally, but imagine that you are graduating students who can recurse, but get a little fuzzy when trying to follow
if(x == 7){
   x++;
}
if (x == 7) {
   x--;
}

Historically speaking, Fortran was more successful than LISP, and C was more successful than Scheme.  Imperative languages resemble the machines they are built upon, and it's only natural, then, that schools in earlier days would have found it important to focus on Turing, Von Neumann, assembly, C, and the like.
Haskell is still trying to prove that it can compile efficiently.  Meanwhile, it's only in the last ten years that lambdas have come to wide acceptance in industry.  It makes sense, then, for both historical and continuity reasons, that schools have focused more on imperative languages.

> **Comments:**
> **username_0**: With modern hardware, the way the system actually works is so different from traditional understanding, that I think it's actually counterproductive to think about it.  From superscalar architectures to branch prediction and multi-core platforms, the way a CPU works internally is now very complex.  I think it's better to let the computer engineers think about how the hardware will work and have computer scientists focus on writing well-designed, maintainable software, especially given the increasingly platform-independent nature of software development.  
> **username_0**: This blog by Raymond Chen (a C developer working on the Windows OS at Microsoft) is informative:  https://blogs.msdn.microsoft.com/oldnewthing/20140613-00/?p=743.  The branch predictor will completely change the expected execution of your code anyway, so best just not to try to anticipate the hardware behavior and focus on the quality of the software.  
> **username_9**: @AaronM.Eshbach You mean the Software Engineers? Computer Scientists shouldn't be particularly focused on writing software well-designed, maintainable software unless that is their area of focus/research. Computer Scientists *should* be focused pretty squarely on understanding complex interactions, algorithms, and computation. Branch prediction and superscalar architectures are great areas of modern interplay between CS and engineering.  
> **username_0**: Perhaps Software Engineering would be the more appropriate discipline.  There wasn't really a Software Engineering major when I attended university, so I don't know what that covers.  At the school I attended, Computer Engineers took a blend of hardware and software courses (including Digital Design and working with FPGAs, etc.) while Computer Scientists took almost entirely software courses, with some basic education on K-maps and the like.  
> **username_9**: @AaronM.Eshbach Yeah, my major was not dissimilar. But things seem to be improving on this front. More schools are offering legitimate SE degrees, which really has blossomed into its own distinct field. I'm hopeful that this shift should be freeing CS majors to spend more time engaging in theory.  

---

### Answer by username_10 on 2018-05-16. Score: 1

The computing ecosystem keeps making smaller and smaller things. Imperative programming is far better matched to Arduinos and other small cheap computers that a k12 and earlier student is likely to tinker with (as opposed to just be a user of).

> **Comments:**
> **username_11**: Today's tiny Arduino is much larger than the big computer we had here when I was a student... even my old cellphone has more oomph.  
> **username_10**: Might be an interesting project to replace Wiring with a Lisp/Scheme derivative.  Anyone done that yet?  Will it fit any Atmel AVR?  
> **username_11**: I've got Maxima (a largeish Common Lisp program) running on my cellphone. It is far from the largest application there...  
> **username_10**: Contemporary mobile phones have more compute+memory than not-to-distant supercomputers (Cray YMP, et.al.).  Whereas an Arduino chip might have only 2k of RAM.  
> **username_10**: Added: I would not be surprised if a lack of appreciation for the disadvantages of functional programming might be a significant contribution to increasing global CO2 emissions, due to inefficient use of vast amounts of data center hardware.  

---

### Answer by username_11 on 2018-05-18. Score: 1

It is just that we *think* procedurally. We "go to the store", we "cook dinner", we "do the dishes", and so on. The functional, recursive, based on induction, mathematical, thinking is very far from natural (ask any teacher of mathematics to students in first-year calculus courses, take a peek at what the colleagues of the math department think about their freshmen). Sure, programming is (thinly disguised) math, and so math style (functional programming) is more "natural" *if you have groked math*. Most people never get it.

> **Comments:**
> **username_0**: I'm not sure your examples illustrate a difference between functional and imperative programming.  Your verb-phrases would all be function names, the only difference is that in FP, instead of mutating the state of "my location", "dinner", and "the dishes", the functions would return the "my new location", "the cooked dinner", and "the washed dishes".  If you wanted to do those things in order and pass the groceries we bought at the store into "cook dinner" and the dishes from dinner into "do the dishes", we just use composition.  
> **username_11**: @AaronM.Eshbach, you *can* model it that way, but it is a world away from how you naturally *think* about it. "I have a bunch of functions that input a whole world and spit out another" isn't the way we think, we think of changing an tiny corner of a (mostly unchanging, totally irrelevant) world, one step at a time.  
> **username_12**: You could say that most of the world around us might as well be a vast collection of global constants and methods that we either are not aware of at all or at least not allowed to run. Finding something that actually *responds* is probably most of a baby's first 2 years of existence. So Procedural makes sense in that way. And, we don't just line up grocery shopping, cooking and washing dishes and push one button and walk away with a full belly and clean new kitchen, we have to push and pull every object and verify that every dish is clean. Not to mention biting the inside of your mouth (bug).  
> **username_13**: It always seems not good to me when assertions are made about "we" as in all humans; evidence suggests that for any imaginable feature differing options exist. The correspondence between sequential thoughts and state transitions holds only at a very initial level and I believe it's the root of the difficulty so many students meet. Furthermore speaking simply from *my* point of view what you say is not true, I think functionally. In my very first moments with programming I was surprised that C did not behave like Haskell, which I didn't know: I would have appreciated to be shown it existed.  

---

