We use cookies to give you a better experience, if that’s ok you can close this message and carry on browsing. For more info read our cookies policy.
4.4

University of Glasgow

Skip to 0 minutes and 6 secondsJEREMY: Do you want to know something upsetting? Programs fail. Yes, computation often goes wrong. Haskell provides several mechanisms for handling computations that fail. The first-- probably the simplest such mechanism-- is called Maybe.

Skip to 0 minutes and 28 secondsLet's think about how a computation might fail. Imagine trying to process a list somehow. Say, take the first element of the list. And you are given an empty list. There isn't any first element. Or imagine dividing two integers and the divisor is 0.

Skip to 0 minutes and 51 secondsWe need a way to capture whether or not such a computation has succeeded or whether it's failed. This is the job of Maybe.

Skip to 1 minute and 2 secondsLet's have a look at this data type. It's defined in the Haskell prelude. The standard library for Haskell. So here I am in Google. I'm going to type in Haskell prelude and Maybe. Wait for the results. And the first hit is the Hackage site which is the official documentation for the Haskell platform. Let's click on that. And here we are. Documentation for the prelude standard module. Let's search in here for Maybe. Here we are. And we see that Maybe represents or encapsulates an optional value. So the value might either be Just a, for some a. Or it's empty which is Nothing. The documentation goes on to say, using Maybe is a good way to deal with errors or exceptional cases.

Skip to 2 minutes and 0 secondsSo these are the type constructors. Either Nothing or Just a. We can look at the source as well. Let's click here and have a look at the source for Maybe. And this is very familiar to us as an algebraic data type. Similar to the ones that we defined earlier on in the course. Maybe is either Nothing or Just a. For the type variable a. And again, we have these two type classes that Maybe derives. Eq for equality. And Ord for comparison. Right. Let's have a play with Maybe. Imagine we want a function to find the maximum value in the list. Perhaps a list of integers. Let's start off by defining the maxhelper routine.

Skip to 2 minutes and 57 secondsSo maxhelper is going to take an integer value which is the maximum we've seen so far. And an integer list which is the rest of the list we still have to process to look to the maximum value. And it's going to return an int, which is the maximum value over the whole list. So maxhelper. If we're given an interim maximum and there's nothing else left to look at, the list just returns x. That is the maximum. Maxhelper with an interim value x and a nonempty input list is going to call itself recursively.

Skip to 3 minutes and 38 secondsAnd the interim maximum is either going to be x or y depending on which one is larger. And then we'll process the rest of the list.

Skip to 3 minutes and 51 secondsSo let's just try this code to see if it works. Sorry. I'm going to start an interactive prompt inside my emacs session and I"m going to run ghci. And I'm going to load max.hs which is where that code is stored. So I can say type maxhelper. There we go there. And I can run it-- maxhelper. So if I give it a value to an empty list, it should return that value as the maximum.

Skip to 4 minutes and 29 secondsIf I give it a value that's small, then I give it the list. Right. I've said minus 1. So I need to put that inside brackets. That's interpreted correctly as an integer value. So maxhelper with an interim maximum of minus 1 and a list 1, 2, 3 returns 3, and so on. Let's go back to the source code now and define a second function, which is called maxfromlist.

Skip to 4 minutes and 58 secondsThis is only going to take an integer list and it's going to return the maximum value in that list. It's going to use maxhelper to find the maximum value. So maxfromlist. If it's supplied with an empty list what's it going to return? I've got a problem here. There is no maximum to return. So let's return nothing. And let's say our return type has now become Maybe int. Because we can only return an int if there is a maximum. And if there isn't, we'll have to return Nothing. Maxfromlist. If there are elements in list then it's going to return maxhelper. I need an equal sign there. Sorry. Equals maxhelper x. The interim maximum xs-- the rest of the list.

Skip to 5 minutes and 56 secondsAnd I need to wrap this up inside the Maybe. So I need to say it's going to return Just this integer value. Good. So let's go back to our ghci session. And let's say, reload. Which will reload the edited max.hs source code. And now I should be able to say maxfromlist 1 2, 3, And that returns Just 3. Good. If I say maxfromlist empty list it returns Nothing. Great. This works fine. The Maybe type means that the type checker guarantees client code will check the result of the computation. Probably with a case expression. This is much more robust than C error codes.

Skip to 6 minutes and 48 secondsRight. Once we've generated Maybe values, how do we propagate them in programs? Perhaps by using lots of case statements. But surely there must be a better way. And there is. At this point I will mumble the word monads. But we'll cover these in more detail in week six. For now let me show you how you can map functions over Maybe values. So let's say let function inc equals one plus.

Skip to 7 minutes and 25 secondsSo the type of inc in the context of the type variable a that is an instance of the number type class. Then inc takes an a and returns an a. So if I say inc 1 it returns the value 2. How about if I say inc Just 1? Look. It doesn't work. So inc can't be applied to Maybe values. However, if I use the fmap function-- this is a higher order function here-- inc Just 1. I get back Just 2. So fmap allows inc to be applied to the value inside the Maybe. The 1 inside the Just 1. Fmap inc Just 2 returns Just 3. And now you're saying, what happens if I apply inc 2 Nothing? Guess.

Skip to 8 minutes and 40 secondsI get back Nothing. Great. Let's leave Maybes there for now. We'll come back to them and monads in general later in the course. Thanks. Bye.

Dealing with Uncertainty

What do we do when computations fail to generate results? Examples include taking the head of an empty list, or finding the minimum value of a tree which turns out to be a Leaf.

Haskell provides Maybe values, which allow us to denote missing results with Nothing. This is type-safe, so much better than null in C-like languages. Maybe is like Option in Scala.