<p>I undertook this study myself about a year ago. I started working through the Programming Languages MOOCs on Coursera (<a href="https://www.coursera.org/learn/programming-languages-part-a/home" rel="nofollow noreferrer">Part A</a> <a href="https://www.coursera.org/learn/programming-languages-part-b/home" rel="nofollow noreferrer">Part B</a> <a href="https://www.coursera.org/learn/programming-languages-part-c/home" rel="nofollow noreferrer">Part C</a>), which are based on <a href="http://courses.cs.washington.edu/courses/cse341/17sp/" rel="nofollow noreferrer">a UW course of the same name</a>.</p>

<p>I didn't really know what I was getting into, but it sounded interesting. Before I knew it, I was learning a radically different approach to programming first with SML and now with Racket (Ruby is up next). </p>

<p>Here are some of the key ideas that were a major departure from my having programmed in C and Python:</p>

<ul>
<li><strong>Avoid mutation.</strong> Over and over again the professor emphasizes why mutation is a bad thing (or at least potentially problematic). From the world of C where I learned about declaring and updating variables almost immediately, this forced me to think differently about the information my programs contained and processed.</li>
<li><strong>Don't call them variables.</strong> As a continuation of the above, they aren't variables (because after all they shouldn't <em>vary</em> because they don't mutate); rather, call them "value bindings." Moreover, these value bindings exist in an <em>environment</em>. This latter idea is essential (and has only recently sunk in) for understanding function closures.</li>
<li><strong>Think recursively.</strong> Of the 3+ assignments I've completed for Part A and Part B, thinking recursively has been an essential component for creating elegant, efficient solutions. Indeed, in some cases it's been the <em>only</em> way to solve a problem thanks to the goal of avoiding mutation. This is not to say that recursion doesn't exist in other languages (because it obviously does), but it's been a more fundamental element to the design of solutions using functional programming languages.</li>
</ul>

<p>Those are my big three; I'm sure there are more. Obviously understanding anonymous functions, higher-order functions, first-class functions, and all that comes with them (e.g. currying) is what functional programming entails. However, this content wasn't a "rewiring of old habits" in the same way that the above points were.</p>

<p>For what it's worth, I appreciate what C has taught me about what happens on a lower level, but I think studying a functional language <em>qua</em> an approach to programming has made me an overall better programmer.</p>

CC BY-SA 3.0
2017-07-17T20:10:27.940Z
2017-07-17T20:10:27.940Z
Peter
<p>When I created my course for Scheme (under not dissimilar circumstances from yours), I used <a href="http://rads.stackoverflow.com/amzn/click/0262560992" rel="nofollow noreferrer">The Little Schemer</a> as my primary source.  The book itself rapidly became too dense for my HS students, so I designed my lessons around each chapter.</p>

<p>My course, then, like the book, took the students slowly through a very foreign landscape. We took no effort to <em>translate</em> imperative programming at all.  Instead, we were <code>cons</code>ing and <code>cdadr</code>ing up a storm, playing with lists, playing with atoms, and creating tiny programs in this alien (elephant-ridden) landscape together.</p>

<p>There was a downside to this, however: because it was presented in a truly functional paradigm, my students did <em>not</em> advance quickly, and did not become nearly as capable in Scheme as they were in Java, Javascript, or C.  They just couldn't get the breadth and depth of experience within the functional idiom over the course of two months that they could with imperative programming in two years. Nevertheless, the work that they did truly was native Scheme.</p>

CC BY-SA 3.0
2017-07-17T19:37:24.650Z
2017-07-17T19:37:24.650Z
Ben I.
<p>I taught a "Functional Programming" course on multiple occasions. It was basically a Haskell course. Phew, can't wait to teach it again.</p>

<p>To answer you question precisely: you have no state, no classes and no usual OOP model. You have to abstract things much more than you are used. Oh, and there is this weird syntax. I mean---</p>

<pre><code>uncurry f a b = f (a, b)
</code></pre>

<p>But that's all typical beginner's problems. In my experience, any computer science student worth her salt would overcome this. The <strong>real</strong> hurdles start later. My answer gets a but Haskell-focused, sorry.</p>

<p>The first killer are monads. Actually, I introduce first type classes, which are sometimes a bit hard to grok, and then enter monads. You can feel the class dropping their high spirit at this. Even if I am quite proud with my way of coping with monads in this class.</p>

<p>It is basically the equivalent of pointers, if the old spoken take in CS is to be trusted. Pointers are hard and there are students who get stuck on them for longer. Same with monads.</p>

<p>Then, if you can do both "normal" style Haskell and monadic, you are good for a prolonged period of time. You have state now. You can do IO. By the way, <code>State</code> was also a quite hard thing to warp their mind around for the students, but I'd toss it into the "monad" box.</p>

<p>What else? Arrows feel like a yet another "monadic" hurde. And they most surely are. But by then the students are quite battle-hardend and have not so many problems.</p>

<p>What I would expect to be a problem, but what was not, were higher-order functions. All these operations on lists and such. And lambdas on the level of a language construct. The lambda calculus is a fully different story, also hard. But that's probably a deviation, as it was a quite theoretical block in an else quite practical course.</p>

<p>A bit problematic, but that's an accomodation problem in my opinion is the applicative programming and all that point-free code golf in Haskell. But if done in moderate amounts and properly explained, students mostly find their fun in it.</p>

CC BY-SA 3.0
2017-09-01T22:58:27.703Z
Welcome to CSE Stack Exchange! You obviously know a lot about Haskell, but you may want to focus your answer more on procedural habits to break, rather than the most difficult concepts to teach in Haskell.
Ellen Spertus
CC BY-SA 3.0
2017-09-01T23:28:23.963Z
Thanks. The somewhat hidden message of my answer was exactly that breaking habits happens in the beginning of the course, I would say, first quater. But the problems with learning a functional language do not stop there. To name such a "procedural/OOP" habit: syntax, of course!
Oleg Lobachev
CC BY-SA 3.0
2017-09-01T22:27:00.243Z
2017-09-01T22:27:00.243Z
Oleg Lobachev
<p>I have a class undergraduate students (2nd and 3rd year) who have had at least two terms of college/university level programming courses using a procedural programming language (typically C++), and often a term or two in other languages, also procedural. They have usually, though not a requirement, taken programming in high school, which was also based on one or another of the procedural languages. In the other computer classes they might have taken, or be taking concurrently, they have a procedural language as a secondary exposure. For example, the web design classes use JavaScript and PHP extensively. Bottom line is that these students are well versed (indoctrinated) in the imperative paradigm.</p>

<p>Now I have to teach them functional programming, and help them to adjust to a new way of thinking about the problems and solutions. In other words, I want them to be able to write a Scheme program, not a C++ program <em>translated</em> into Scheme.</p>

<p>So then, the question here is this: <em>in the switch from procedural to functional programming, what are the critical "habits" to change in the students' minds so that they are able to grasp the functional paradigm enough to get them programming in the new language rather than writing old programs in the new style?</em></p>

<functional-programming><programming-paradigms><imperative-programming><scheme>
What 'procedural' habits to break when teaching 'functional' programming?
# What 'procedural' habits to break when teaching 'functional' programming?

(Asked by: username_0 on 2017-07-17)

I have a class undergraduate students (2nd and 3rd year) who have had at least two terms of college/university level programming courses using a procedural programming language (typically C++), and often a term or two in other languages, also procedural. They have usually, though not a requirement, taken programming in high school, which was also based on one or another of the procedural languages. In the other computer classes they might have taken, or be taking concurrently, they have a procedural language as a secondary exposure. For example, the web design classes use JavaScript and PHP extensively. Bottom line is that these students are well versed (indoctrinated) in the imperative paradigm.

Now I have to teach them functional programming, and help them to adjust to a new way of thinking about the problems and solutions. In other words, I want them to be able to write a Scheme program, not a C++ program *translated* into Scheme.

So then, the question here is this: *in the switch from procedural to functional programming, what are the critical "habits" to change in the students' minds so that they are able to grasp the functional paradigm enough to get them programming in the new language rather than writing old programs in the new style?*

**Tags:** functional-programming, programming-paradigms, imperative-programming, scheme


---

## 3 answers

### Answer by username_1 on 2017-07-17. Score: 4 | Accepted answer

I undertook this study myself about a year ago. I started working through the Programming Languages MOOCs on Coursera ([Part A](https://www.coursera.org/learn/programming-languages-part-a/home) [Part B](https://www.coursera.org/learn/programming-languages-part-b/home) [Part C](https://www.coursera.org/learn/programming-languages-part-c/home)), which are based on [a UW course of the same name](http://courses.cs.washington.edu/courses/cse341/17sp/).

I didn't really know what I was getting into, but it sounded interesting. Before I knew it, I was learning a radically different approach to programming first with SML and now with Racket (Ruby is up next).

Here are some of the key ideas that were a major departure from my having programmed in C and Python:

* **Avoid mutation.** Over and over again the professor emphasizes why mutation is a bad thing (or at least potentially problematic). From the world of C where I learned about declaring and updating variables almost immediately, this forced me to think differently about the information my programs contained and processed.
* **Don't call them variables.** As a continuation of the above, they aren't variables (because after all they shouldn't *vary* because they don't mutate); rather, call them "value bindings." Moreover, these value bindings exist in an *environment*. This latter idea is essential (and has only recently sunk in) for understanding function closures.
* **Think recursively.** Of the 3+ assignments I've completed for Part A and Part B, thinking recursively has been an essential component for creating elegant, efficient solutions. Indeed, in some cases it's been the *only* way to solve a problem thanks to the goal of avoiding mutation. This is not to say that recursion doesn't exist in other languages (because it obviously does), but it's been a more fundamental element to the design of solutions using functional programming languages.

Those are my big three; I'm sure there are more. Obviously understanding anonymous functions, higher-order functions, first-class functions, and all that comes with them (e.g. currying) is what functional programming entails. However, this content wasn't a "rewiring of old habits" in the same way that the above points were.

For what it's worth, I appreciate what C has taught me about what happens on a lower level, but I think studying a functional language *qua* an approach to programming has made me an overall better programmer.


---

### Answer by username_2 on 2017-07-17. Score: 3

When I created my course for Scheme (under not dissimilar circumstances from yours), I used [The Little Schemer](http://rads.stackoverflow.com/amzn/click/0262560992) as my primary source. The book itself rapidly became too dense for my HS students, so I designed my lessons around each chapter.

My course, then, like the book, took the students slowly through a very foreign landscape. We took no effort to *translate* imperative programming at all. Instead, we were `cons`ing and `cdadr`ing up a storm, playing with lists, playing with atoms, and creating tiny programs in this alien (elephant-ridden) landscape together.

There was a downside to this, however: because it was presented in a truly functional paradigm, my students did *not* advance quickly, and did not become nearly as capable in Scheme as they were in Java, Javascript, or C. They just couldn't get the breadth and depth of experience within the functional idiom over the course of two months that they could with imperative programming in two years. Nevertheless, the work that they did truly was native Scheme.


---

### Answer by username_3 on 2017-09-01. Score: 3

I taught a "Functional Programming" course on multiple occasions. It was basically a Haskell course. Phew, can't wait to teach it again.
To answer you question precisely: you have no state, no classes and no usual OOP model. You have to abstract things much more than you are used. Oh, and there is this weird syntax. I mean---
uncurry f a b = f (a, b)

But that's all typical beginner's problems. In my experience, any computer science student worth her salt would overcome this. The real hurdles start later. My answer gets a but Haskell-focused, sorry.
The first killer are monads. Actually, I introduce first type classes, which are sometimes a bit hard to grok, and then enter monads. You can feel the class dropping their high spirit at this. Even if I am quite proud with my way of coping with monads in this class.
It is basically the equivalent of pointers, if the old spoken take in CS is to be trusted. Pointers are hard and there are students who get stuck on them for longer. Same with monads.
Then, if you can do both "normal" style Haskell and monadic, you are good for a prolonged period of time. You have state now. You can do IO. By the way, State was also a quite hard thing to warp their mind around for the students, but I'd toss it into the "monad" box.
What else? Arrows feel like a yet another "monadic" hurde. And they most surely are. But by then the students are quite battle-hardend and have not so many problems.
What I would expect to be a problem, but what was not, were higher-order functions. All these operations on lists and such. And lambdas on the level of a language construct. The lambda calculus is a fully different story, also hard. But that's probably a deviation, as it was a quite theoretical block in an else quite practical course.
A bit problematic, but that's an accomodation problem in my opinion is the applicative programming and all that point-free code golf in Haskell. But if done in moderate amounts and properly explained, students mostly find their fun in it.

> **Comments:**
> **username_4**: Welcome to CSE Stack Exchange! You obviously know a lot about Haskell, but you may want to focus your answer more on procedural habits to break, rather than the most difficult concepts to teach in Haskell.  
> **username_3**: Thanks. The somewhat hidden message of my answer was exactly that breaking habits happens in the beginning of the course, I would say, first quater. But the problems with learning a functional language do not stop there. To name such a "procedural/OOP" habit: syntax, of course!  

---

