# Scheme vs Haskell for introducing functional programming

So, I am not interested in which language is better, because that is a matter of opinion. What I care about is whether making a switch from Scheme to Haskell will directly help me accomplish my goals. What programming language concepts does each language bring to the fore?

So, I am seeking input from folks who have taught using these languages about the kinds of experiences they had. How did the language features of Haskell or Scheme make your students' experience better (or worse)?

For context, my kids come into their junior year knowing Java, C, and Python pretty well. For their junior year, it was decided that there should be a course in theoretical computer science. In order to have labs, I further decided that we should move away from imperative programming and expose the kids to a functional language. So, while the class was not about functional programming, the kids did quite a lot of it.

I used Scheme (DrRacket, to be specific), but over the course of the year, I found that kids were sneaking set functions into their labs, which ran (to my thinking) counter to the goals of the class. I was also a little displeased with the rather unintuitive way that boolean functions and contracts interacted in the language.

I have, as a result, been thinking about migrating over to Haskell. If I did this, I know that I would need to redesign my labs (and I wonder if the Turing Machines I have them design would suddenly run very slowly!)

But, other than not having a set function, what other benefits might Haskell bring to my students? I don't mind putting in the work to redesign the course if there is a sufficient benefit.

• I see that people are voting to close, but I'm not sure why - are they actually suggesting that there are not pedagogic implications of language choice that are not purely subjective? Surely, Java is a better language to begin teaching Object Oriented Programming than C. Different languages have different features, and these choices have real educational implications.
– Ben I.
May 24, 2017 at 4:07
• This seems like "Good Subjective." I had a similar struggle this year choosing between PHP and Python for a particular unit. Based on the context such a question would certainly have objectivity and research to support one appoach over the other. May 24, 2017 at 5:36
• My answer below composed from bits and pieces written at different times Depending on interest can refactor as appropriate
– Rusi
Jan 30, 2022 at 16:27

## 4 Answers

I suspect there'll be more universities switching from Scheme to Haskell for introductory functional programming (FP) courses, mainly for the 'real world' appeal of Haskell. I see 15 mentions of Scheme and 16 of Haskell in the recent SIGCSE programming language poll results, although Scheme (as Racket) still has the edge in introductory courses.

We've a little FP in one of our A-level (secondary school leaving exam) CS courses in the UK, and Haskell seems the popular choice; indeed I'm not aware of any schools using Scheme for this. I know of one school that's been using Haskell with six year olds(!). In the US at school level, Scheme (as WeScheme) features in Bootstrap World, but they're using Pyret for some courses now.

There are some good Haskell texts around, e.g. Hutton's Programming in Haskell, and Lipovaca's Learn You a Haskell for Great Good! (free online version), but these are introductions to the language rather than introductions to functional programming - it still seems hard to beat SICP, which is Scheme based. What text are you using at present?

Interestingly, this critique of SICP from 1987 identifies four issues with Scheme, all of which are addressed in Haskell:

1. Pattern-matching.
2. A syntax close to traditional mathematical notation.
3. A static type discipline and user-defined types.
4. Lazy evaluation.
• We're using The Little Schemer, which is a wonderful little book! I shall miss it if I switch.
– Ben I.
May 24, 2017 at 5:41
• See pp 60-61 of Hello World #2 May 24, 2017 at 8:36
• Just to be clear, Pyret and Racket are not in opposition. We created Pyret because we were tired of having arguments about the virtues of parenthetical syntax and decided to give people a non-parenthetical alternative that is very similar in many ways, though of course having "forked off", we did feel free to make some changes that don't violate the spirit of the Racket tradition. Bootstrap uses both Scheme and Pyret. Bootstrap:Algebra is and will always be in Scheme syntax. The :Reactive, :Physics, and (new) :DataScience curricula are all in Pyret. Jun 4, 2017 at 0:30
• While I have great respect for Wadler's critique, I don't treat it as gospel. It's unsurprising that it aligns with Haskell! In particular, I do not view either static types or laziness as critical, and they can in fact be very problematic too. As for user-defined types, Racket has long since broken with Scheme on that front, as does Pyret (which also has algebraic datatypes). In short, there's a complex design space here. Jun 4, 2017 at 0:32
• To this answer I would add that Haskell is simply easier to read and strongly typed, both things that I find helpful for beginners. Mar 8, 2018 at 12:54

As the kids these days would say, you're doing it wrong.

Let me explain.

As I've commented elsewhere, every "full language" has a whole bunch of things that educators would find inconvenient or undesirable. Your Haskell students can use monadic state or UnsafePerformIO too! So Haskell is "just as bad" in principle.

That's why Racket (in an explicit departure from Scheme) gives you the means to define your own languages, and DrRacket ships with several student pedagogic languages already built in. The first few grow in power to the point of being very powerful — but not having set! at all. Only near the end of the pedagogic language tower do you find set! (and its structure mutation variants). Until then, the feature is literally not present. For instance, in BSL (Beginning Student Language), here's a program interaction:

> (define x 3)

> (set! x 5)

set!: this function is not defined

DrRacket is saying "you've put something in the function application position called set! and I don't know what it is" — the same error as if you had written (foo x 5) instead. That is, it's not even saying "sorry, I don't allow you to use state yet"; it's saying "state literally does not exist in my world". Because, at that level, it honestly does not.

So the sense in which you're doing it wrong is that you're using the wrong language level. Your programming environment ships with languages that explicitly preclude the use of state. Instead of using them, you're giving your students the full, unrestricted force of an language in industrial use. It's no surprise that they will find various features in there that you don't want them to. (Sadly, there are no "language levels" for Haskell that can keep students from some of the ugly corners of that language, but the principle applies to every language.)

There are many more trade-offs between using Racket and Haskell, but this one is easily addressed. (Note that I said Racket, because it's Racket's enhancements over Scheme that enable us to create these kinds of language levels. And with very little effort, you could too, if you didn't like the ones we provide.)

Although Scheme does have a set function, you don't need to allow students to use it. Obviously, set, print, begin and loops are all potentially very useful for debugging, but it's OK to tell them that they are not allowed to set other than when debugging. Thus, you don't need to change your language if all you want is to stop students from abusing set, especially if you're doing great with Scheme!

On the other hand, there are a few problems if you choose Haskell over Scheme:

• I/O. Either you have to present it as a "black box" without explaining how it works, or you have to explain monads to them, which could be confusing for FP beginners.
• Stateful programming. Although FP aims to be stateless, oftentimes states are useful in creating real-world programs. Again, to do this in Haskell, you can't get around monads. If students overuse set and begin, tell the students they may not use them at all!
• Cleaner type system. No type classes and the like.
• Again, SICP and the Little Schemer are really nice; HTDP is also great.

Meanwhile, have you considered the ML family? SML and OCaml could be interesting choices too. ML has mutable references, but no mutable variables; but you don't need to tell them about refs!

• TBH, I don't know what monads are. I personally learned FP using SML decades ago, but utilization is so low today... there are many fewer resources around, so I chose to steer clear. As someone who does not consider myself to be 100% solid, I thought that I might really need those resources :)
– Ben I.
May 24, 2017 at 10:31
• @Choirbean You may want to try OCaml then. There are lots of resources (like Real World OCaml, etc) and a quite large community for it. As for SML, it hasn't died, but all available resources (e.g., Ullman) are quite dated. May 24, 2017 at 17:26
• In terms of SML, there is a MOOC on Coursera, Programming Languages Part A. I completed the course for my first dive into functional programming and really enjoyed it. The other two parts focus on Racket and Ruby, respectively. There are great videos, lecture notes, exercises, etc. Plus, it taught me Emacs, which I found valuable. Here's a link: courses.cs.washington.edu/courses/cse341/17sp May 24, 2017 at 21:09

Below written from pov that functional programming (FP) is the only way to go. This is of course not literally true. But people of other viewpoints can express their's better than I can. So I'll stay with mine; here goes!

# Constructing the Ideal CS-101 language

The PL-no-1 becomes willy-nilly the mentalese or Language of Thought for the student for their life. Or at least for a long time after. So it behoves us to make good choices here!

Following are the desiderata I consider key and the closest corresponding ideal language. Here's a wider set. I invite you to think through your own personal set. Main point being: Decide your attributes before your language.

The medium for CS-101 should:

1. Have low bar on use : Python
2. Have clean type inference : ML
3. Be conceptually simple : Scheme
4. Have rich expressions : APL
5. Have a mathematical (aka equational) feel : Haskell

Scott Rowe (and like-minded) will exclaim: Where in all this is...

# The machine that makes this world possible?!

Yes machine understanding matters. But postponing that causes less damage than reversing the order to machine-first and have students get into the bad habit of getting hung up on implementation/efficiency questions and neglect semantics. This is of course the point around which the maximum amount of disagreements and disputes occur. I don't claim to be without bias. I only claim to be on the better side😉.

My slogan here:

# Ontology before semantics

This answer will make sense if that is agreeable. If its not you probably want to stop reading here!

The first part of the slogan is sufficiently over quoted that I can leave it alone. The second is less known... And more important

When we teach there are two things that interact:

• the concepts we wish to teach
• the key-elements of the PL used

Both these are the ontologies though from different domains. When they gel the flow is smooth: rewarding to teacher, illuminating to student. When not it becomes like Bernard Shaw's pig metaphor:

Never wrestle with a pig. You get dirty, and besides, the pig likes it.

The last may be unverifiable but the rest stands

When the course objectives (teacher ontologies) and the PL's ontologies mismatch everyone suffers

An example: Lists ("singly linked lists") in C start with:

struct node
{
T elem;    /* Whatever T may be */
struct node *next;
};


Did you notice that there are TWO types there? No?? Let me spell it out

typedef node *nodeptr;
struct node
{
T elem;
nodeptr next;
};


Which of node and nodeptr is the concrete C model for the abstract list type?
Now you may consider this a hairsplitting question but it becomes key from the ontology pov. Because from the ontology-pov the abstract list type falls between the two concrete C types node and nodeptr.

In effect then all of C is coding up around the fact that:
Not only C has no lists; it does not even have user defined lists

[If you disagree with that look at Greenspun's tenth rule]

IOW I discard the machine-first without much compunction.

I also discard the OOP-first philosophy. Justifications for this are for elsewhere...

# Other Desiderata

But there are other desiderata that are more real. I happen to choose to de-prioritize them. Others may — justifiably — choose otherwise. For example

1. FP is proverbially a good fit for parallel programming. If this matters Erlang will come high on your list. And if high becomes highest — great!
2. Real world considerations invariably push against academic ones:
• Must be under JVM : Scala, Clojure
• Windows/.NET are my world : F#
3. You really want to push the FP envelope at its research-edges? Idris, Agda
4. The main action is at meta level (you are a devotee/disciple of Paul Graham)? Common Lisp
5. Etc.

There are dozens (maybe hundreds) of other attributes we could study.

All these have their legitimate provenance. They are just not important enough for meat the moment. [I wouldn't put it past Idris/Agda taking over the mantle of Haskell in 2035]

Problem with OOP: You wanted a banana. You got a gorilla holding the banana and the entire jungle.
Joe Armstrong

My general suggestion would be towards this: You wanted FP. You chose Haskell. Did you want the 700lb gorilla?

This is usually taken as the FP-er Armstrong bashing OOP

I am turning it round to and applying it to Haskell! There's just way way way too too much there. For the sophisticated programmer it could be joyous like slurping around Willy Wonka's chocolate factory. To the beginner its more like getting drowned.

# Scheme

The trouble is that scheme really doesnt cut it as an FPL by 2022 standards.

Much of Scott Rowe's continual tirades against scheme come from this: If they (SICP) were going to introduce assignment on pg 300 and invalidate those earlier 300 pages why did they waste my time?

The problem — this problem — vanishes in Haskell: You cant do assignment/mutation… pg 3 Or 300 Or 3000. Not possible. Its just not there.

The question is a non-trivial one; viz: How far to push in important desiderata? Informally into the culture? Or all the way formally into the language definition?

At the broader level the view (to me at least) is murky.
At the beginner level its quite clear Haskell gets (this aspect!) righter than scheme

So then…

# Haskell → Haskellish

Haskell is great but Haskell has lost its way into labyrinthine complexity of its legendary type system. See

• Erik Meijer Popular MOOC on FP
• Mark Lentczner resignation from release manager for The Haskell Platform
• Simple Haskell A bunch of folks feeling similarly
• Google for ftp/amp for more nittygritty details about the controversy eg

My summary:

As a teacher, I wish to stay Haskell-ISH but not Haskell proper as in current ghc at least for CS-101. [Projects is another matter]

Below I suggest alternatives for those who are convinced that Haskell-style FP is the way to go but not ghc itself (for now)

# Nearest to Haskell

## Miranda

The original small super elegant expensive proprietory predecessor of Haskell. Recently open sourced. Strongly recommended for teaching basic programming via FP. A natural first choice for people who regard Bird&Wadler (Ed-1 mind you!) as the best CS book ever See interview

## Gofer

Earliest and smallest language that can claim to be Haskell. See Haskell-gofer error message comparison

The big thing going for it are the series of preludes that make it possibly to sequentially add complexity as Racket does with its teachpacks.

## Pugofer

My changes to gofer which I most use.

No this is not a "shameless plug". Its not documented for public use. Not really usable other than by my students/colleagues.

## Hugs

Can reasonably be called "gofer 2"; falls between gofer and full (modern) haskell; a very sane choice for people going functional; as Erik Meijer demonstrated a few years ago

## Helium

Similar goals to pugofer in terms of beginner simplicity. See

## Pure

When we get that the whole business of using FP as a general programming ideology is using math equations as a term reqriting system, an explcit rewriting-oriented language becomes an attractive choice. Pure is one such.
[No first hand experience]

# Wider Span

• Erlang : When concurrency is central
• ML family (SML Poly-ML, CAML, OCAML) : the original FPLs. In many ways neater than all the rest.
• Stay within the Java world : Clojure, Scala
• Stay within the .NET : F#

Especially given your:

I learnt FP using SML decades ago

ML-family may be the sanest choice. Conversely using current publicity ratings to determine a CS-101 medium is really egregious. For those who don't see this there's no use to this conversation. For those who do, there's no need. Still it may help to hear a Dijkstra hyperbole:

Programming should be taught with a language not implemented on campus

Now you can ignore that, or take it literally. I hear it as Dijkstra giving us teachers the freedom to cock a snook at TIOBE indices!

# In short my recommendation

For you Ben take ML family if that makes you most comfortable. At least to start with.
[Others can sift the set nearest Haskell to their taste]

I actually like ML family a great deal. Much more teacher-friendly and fad-unfriendly than the modern crop.

Myself I dont use it because I am addicted to Haskell syntax. [My ideal FPL would be an ML-semantics carrying a Haskellish syntax. No such exists that I know] Call me silly but I really want my quick sort to be thusly

qsort []      = []
qsort (x::xs) = qsort [y | y ∈ xs, x<y] ++ [x] ++ qsort [y | y ∈ xs, x≥y]


Yeah my emacs is setup so that when I type <- I get ∈ 😈

• Interesting post, but I was not intending that students should learn about or even care about efficiency by learning a bit about how the machine works at the beginning. It would be just: "Here is how the CPU runs instructions, it's not magic. Any questions? Good..." Then they have the Notional Machine that clears up any possible confusion about variables, assignment and indirection, so those will never give them a problem again. Inoculate them against all these ills the first day. Any questions? Good... Jan 30, 2022 at 18:10
• I'll look at the update and language references. I still just feel that there is something schizophrenic, something reality-denying about trying to sprout wings and fly away from the fact that a computer is an electrical machine. As long as you sneak that in before everything else, and make sure everyone gets it, I'll accept your experience and authority to pile things on top. Without it, your students are "lost in space", in my opinion. Jan 31, 2022 at 11:59
• For FP, abstraction is not a positive. See
– Rusi
Feb 1, 2022 at 3:31