I'd taught a class named "Introduction to Computer Science" for many years. I hated that name. If it were a color, it'd be beige. I wanted a better name. I had an epiphany, and now I have it. The name is "Think Functional!" or "TF!" for short.
Below I describe the core idea of TF!. Don't feel obligated to read all of it, but please do read the section titled Why Python? and those after.
I was excited, for I had before me the solution to a problem that I'd carried with me for four years. But I was also afraid. Afraid that I'd lose it. So I walked to my board and tried to capture its essence. I transcribe:
We're here to solve problems algorithmically.
Algorithmic solutions of any complexity break up naturally into single-task algorithms.
Each of these sub-algorithms should be wrapped up in a function.
A solution is thus a collection of functions. This is the core idea of the book.
Those functions should be simple. I mean that each should perform one and only one task.
Those functions should be safe. I mean that none should modify the state of any variable outside its scope. (Mysterious? All will become clear!)
Those functions should be general. I mean that none should make any special assumption that limits its applicability.
Those functions should be pure. I mean that a function should always produce an output of the same type.
This epiphany became classroom litany - the Litany of the Function
Write functions. Make them simple. Make them safe. Make them general. Make them pure.
I hope my students will forgive me. I hope you will forgive me. They've heard this dozens of times. So will you.
In any introductory CS class, you'll find a cluster of related concepts: data and data type, computation and algorithm, function, iteration, selection and others.
The most important of these, the one through which all the others must be understood, is the concept of a function. (Yes, yes. I know this is only a promise at the moment. I've not proven it. Be patient. The book is the proof.) So let me take a moment to answer the question, What is a function?
Let's turn to mathematics for an example. Recall an old friend, the square function. What's it do? It multiplies a number by itself. Simple? Yes, but let us tease out the stages in this multi-stage process. I'll use the example of the square of 3. First the square function takes the 3. This is its input. Second the square function performs a computation in accordance with a rule. The computation rule here is multiply the input by itself. (Computations need not be numerical. Instead they can be any way in which the input is manipulated. For instance, a computation might take a string of lowercase letters and capitalize them all. More on this later.) Third it gives back a 9, which is the result of the computation. This is its output.
All functions have these three aspects: input, computation, output.
Take care: the square function is a radically different type of object than its input and its output. Input and output are numbers. The function is a rule (multiply by itself) that takes a number and gives another back. The difference here is a radical as that between coq au vin and the recipe for coq au vin. We eat the former. We follow the latter.
I'd guess you've seen the mathematical notion for a function. Let's take a look. In the equation below, "x" represents the input to the function, "y" its output and "f" the computation rule. We then have:
y = f(x)
Read this is as:
y is returned as output when the function f takes x as input
Shorter as:
the value of f for x is y
Shortest as:
f of x is y
I should emphasize a point implicit in what was said above. A function cannot give different outputs if given the same input. We cannot for instance square 3 today and get 9, and then square 3 tomorrow and get not 9. If we ever get 9, we always get 9.
Functions are deterministic and because of this predictable; and since they are predictable, they are verifiable.
I'll make much of verifiability in TF! You'll write many functions, and you'll test each that you write. How? You'll feed them inputs for which the output is known. If they give the right output, this is evidence that they are correct; if they ever give the wrong output, they are thereby refuted.
Our language is Python. Why? My interest lies in problem solutions, and Python provides the quickest route to that.
Let me say a little more:
Python gets you to an attempt at a solution faster than any other language I know. It gets you to your first attempt faster. I gets you to your subsequent attempts faster. (You'll write code. You'll fix the code you've written. Mostly you'll do the latter.)
Python's syntax is minimalist. The result is clean, compact code.
Python is high level. It's all about the logic of the algorithm, baby! You'll never have to dirty your hands with hardware irrelevancies. (Sorry C. You're not the best first language.)
Python is the hippie, do-whatever-feels-right language. Want to write imperative code? Functional? Object oriented? Python's gotcha covered! Beginners need freedom, not the straitjacket of a language like Java. (Java is the buttoned-up, do-exactly-as-your-corporate-masters-tell-you language. Why oh why did the College Board choose Java for its AP class? What a terrible choice!)
Python is easily extended. (Relevant XKCD.) Want more math functions? import math. Want access to time and date data? import datetime. Want a powerful set of tools to write your own game (and who doesn't want that)? import pygame.
You'll need an IDE, which is short for "Integrated Development Environment". This is where you'll write your programs, run them, peruse the inevitable error messages and then debug.
You have IDE options. Many. Honestly it makes little difference which you choose. Need to code in a browser? (My students do. They have Chromebooks.) Try trinket.io, replit.com or codehs.com. Want to install an IDE instead? Go to python.org. Want more power? Pycharm is great. So is Visual Studio Code.
Your IDE will provide you with both a code editor and a console. You'll write your programs in the code editor. Their output will be sent to the console. The console also allows you to execute lines of Python code one at a time. We'll experiment with novel features of Python there, and we'll test our functions there.
Let's try a little experiment to make sure you're ready to go. Got to you IDE and type in the one-liner below into your code editor:
print("Hello World!")
Now run it. That famous sentence should appear. Somewhere. (Don't know where? RTFD.)
Now got to the Python console. Somehow. (Don't know how? RTFD.) The standard Python console prompt is >>>. (You might need to type Python into the console and then hit enter before you get >>>.) Type this in:
>>> 2 + 2
You should get:
4
If both of these worked, you're good to go! If they didn't, RTFD!
As I write, both Python 3 and Python 2 are widely used; and the current version of 3 is 3.10.14.
I assume you'll use the most current version of 3.
In each chapter, you'll read; and in each chapter (except the first), you'll write functions. I provide two ways for you to check your functions. First, under the description of each function, I include a number of test cases. If your functions return the values I say they should, they're likely right. Moreover each chapter (except the first) includes a unit test. What does a unit test do? It tests your functions. How? Copy it, paste it under your functions and then run. The unit test will then generate a text file report; and at the end of that report you'll find your grade. Run as many times as you like; each time, the new report will overwrite the old.
By Chapter 3, you'll know enough Python to take on projects. (Peruse the Project link now if you like. They're the best part of Think Functional! I think.) Do them! I'll teach you bits of Python there that you need to know.
Last, every chapter has a Quiz.
The problem sets might perhaps better be called "function sets". In each except the first, you'll be asked to write a set of functions.
Many will be hard. This is quite deliberate. My aim in TF! is to provide you with a set of tools able to solve computational problems (and that's all Python is in the end, of course), and then set you to work on good problems.
Some problems require that you read quite a bit; typically in those that do, I need to teach you a bit of mathematics.
I also teach a bit of Python in the problem sets, for I find that sometimes the best place to first show you some capability of Python is precisely when you'll need that capability.
Thus, if you wish to really learn how to program from TF!, you really must do the problem sets.
I am a teacher. Let me take a moment to address my colleagues.
I assume that our students are intelligent, interested, disciplined and independent. My goal in TF! is to provide them with tools and then set them loose on good problems.
Do you lecture most days? Stop that! Most days students should be at work on the problems you've set them or problems they've set themselves.
Do you reveal solutions? Stop that! You should at most gently reorient students in a way that will prove more fruitful.
What do you do then? Mostly you do nothing. Teach a little. Help a little. Mostly stay out of the way. As a wise old man once said: "Teaching is like frying a small fish. You spoil it with too much poking." (Actually he said governing is like this, but I don't think he'd mind my change.)
I am a teacher. Let me take a moment to address my students.
Of course you're intelligent. Of course you're interested. But perhaps you don't yet recognize the full extent of your power. You don't need a mama bird that will fill your head with easily digested facts. What you need instead is someone to give you tools, point you at good problems and provide a bit of help when you're stuck. Mostly you'll teach yourself.
How? Well, how do you learn how to ride a bike? You try. You fail. You fix what you did wrong. The same is true here. How do you learn to code? You write code. The code is buggy. You fix the bugs. The teacher teaches a little. But mostly it's you. That's not a bug of TF! It's a feature!