A Very Brief Introduction to the λ-CalculusWhat is this all about?
I’ve been programming in imperative languages since I first started coding back in high-school but until recently I had never worked with a functional programming language. I had a lot of difficulty finding good learning resources about Haskell for people who already know how to program but haven’t ever used a functional programming language. So I decided that I would write one.
Who is this written for?
If you are familiar with an imperative programming language, such as C, C++, Java, or Python, but you’ve never written a line of code in a functional language, this is for you. I hope that you consider learning Haskell, and I hope to make the process easier for you.
What’s special about this blog?
When you start learning Haskell, you soon realize that almost all functions are “pure” and can not produce side effects. Side effects are things other than computing the result of a function; things like reading from the command line, writing to a database, throwing an exception, or displaying a web page. Not allowing side effects by default is a good thing because your program won’t write to a file, access shared memory, or throw an exception when you don’t expect it to. On the other hand, a program without side-effects can not interact with its environment in any way. It can’t take any input or produce any output. In other words, it’s useless.
You then learn that making side-effects is an advanced topic in Haskell, requiring a deep understanding of something with the scary name “monad” and you spend weeks not learning about monads because they’re in the 7th chapter of your Haskell book and you can’t figure out how to get from where you are now to really understanding them.
This is because most beginner resources on Haskell that I’ve encountered will either take you on a grand tour of the language before you ever write a compiled application with I/O, or they will teach you how to write an application up front using imperative-like style without really teaching you how it works from a functional programming perspective.
I don’t think that either of these approaches work well. Both of them frustrated me because even after weeks of learning I didn’t understand how to write a real application with side effects. In my opinion, side effects and monads are not an advanced topic and you should learn them as soon as possible.
So instead of using either of these approaches, we’re going to go from imperative programming to pure functional programming as quickly as possible, and then you’re going to learn how to produce side effects. That way you can start coding your own useful programs in Haskell as quickly as possible, which will be a lot more fun than just sitting around memorizing syntax.
By the way, I am going to have to use all of the scary terms because that’s just how Haskell works, but they really aren’t as bad as you think once you get to know them.
What is Haskell?
Haskell is a language for writing software in general. It is not designed for one specific domain, but, like Python or Java, it can be used in many domains of computation.
- Functional. Functions are first class types in Haskell. They can be passed in as parameters to other functions. The advantage of this is that it tends to create compact code if used correctly.
- (Mostly) Referentially transparent (Pure). This means that functions in Haskell will always return the same value given the same input, regardless of the external state of the world. This feature makes it really easy to reason about functions in Haskell. Most functions in Haskell can’t do anything that isn’t written explicitly in their function body. Also, most functions in Haskell can be written as if they only evaluate to valid results, even when you have to handle potential error conditions.
- (Mostly) Side-effect free. In general, evaluating a function in Haskell will not modify global state or perform any I/O. When such a function would perform a side-effect, the effect is contained safely by a monad (I’ll explain what they are in my third blog post). This is great because many problems which are hard to debug are caused by side-effects, with things like file I/O, data races, and random numbers causing problems.
- Statically and strictly typed. This means that you declare the type of all values in your program at compile-time and values in your program won’t change their type at run-time. This is often seen as a disadvantage by programmers who use dynamically typed languages, but it helps with ensuring that your program is correct even before you run it.
- Lazy. I’ll get into this more later, but expressions in Haskell are only evaluated when they absolutely must be. This was extremely strange coming from a C++ background, but it turns out to be very useful in Haskell.
- Compiled. Haskell produces native binaries, but there is an interpreter included with the standard compiler.
- Garbage collected. This is important to know about, but it isn’t going to affect your life as a beginning Haskell programmer at all.
Haskell is good for you if you:
- Like learning about programming languages. Haskell is a very unique language, and learning about it is a real eye-opener if you’ve been programming in an imperative language up to this point.
- Care about safety and risk. The main reason that I became interested in Haskell is that I work as a programmer in a medical device company. Since Haskell is mostly referentially transparent and garbage collected, many side-effects (crashes, exceptions, etc) in well tested code can be restricted to I/O routines, which generally form only a small part of a Haskell program. This means that you can limit the risk associated with a piece of code, minimizing potential failures to a small part of the program.
- Care about security. Since Haskell is mostly referentially transparent and garbage collected, you can rely on some level of durability against attacks by malicious actors. In well tested code, the potential for unexpected behavior (e.g. crashes) can be restricted to I/O routines only. An example of this kind of crash resistance can be seen in Facebook’s Sigma project, which was re-written in Haskell. (https://code.facebook.com/posts/745068642270222/fighting-spam-with-haskell/)
- Care about concurrency. I’m still too new to programming with Haskell to say that it’s better for concurrency than other programming languages; but the impression I get is that because Haskell is mostly referentially transparent and lazy, concurrent programming is easier in Haskell than many other languages. For example, there isn’t any point having shared memory in Haskell because there is generally no shared state in a program. I’m going to revisit concurrency in a later post.
I started out my Haskell journey at http://learnyouahaskell.com/, which is an excellent resource for beginner Haskell programmers. I also have a copy of http://book.realworldhaskell.org/, which is a great resource about Haskell. You should also know about Hoogle (https://www.haskell.org/hoogle/), the Haskell API search engine, and Hackage (http://hackage.haskell.org/), which is an incredibly arcane list of function signatures for common Haskell libraries.
Getting a Haskell compiler
The first thing you’ll need to do to get started programming is to download the Glasgow Haskell Compiler (GHC) and install it on your machine (https://www.haskell.org/ghc/). The GHC package comes with a compiler, ghc, and an interpreter, ghci.
Haskell files use the .hs file extension, you can compile a Haskell file using the following command on your terminal:
This will produce an executable file called myFile.exe in the same directory.
In order to run the interpreter, type ghci on your terminal or open the application on Windows.
While I think it’s helpful to play around with the interpreter, I also think it’s important that you shouldn’t get too comfortable with it. The interpreter uses special syntax which isn’t available in the rest of the Haskell language; and it behaves sort-of like it’s running an imperative language, which is misleading.
The reason the interpreter is special is because it is implemented using a monad and it will take a few posts before we cover what those are and how to use them. Try some things in the interpreter, but remember that what many beginner resources teach about the interpreter is not “real” Haskell.