In this segment we're going to talk about exceptions, which are what you use when you have a run time condition that should be an error. We'll talk about how to create exceptions, how to raise them, which is called throwing in many languages, and how to handle them, which is called catching in many languages. And this is a reasonable place in the course to put this, because the way ML does exceptions is very similar to how it does data type bindings although exceptions are a separate concept. So let's explain most of this with the code and then we'll summarize what we see with a couple of slides. So first, let me show you how the function head, is actually implemented. So remember what head does, it takes a list. The list is not empty, it returns the first element. If it is empty, it ends up raising an exception that happens to already be defined and called list.empty. So here is exactly how I expect the code in out ML standard library to be implemented. Just as a case expression. In the case of a non empty list, it returns x. But for the empty list, it uses this raise key word, followed by the exception. And indeed, if we had a call of head with the empty list, head would never return. Because what raise does is cause an exception to occur instead, alright? So list.empty was just defined by whoever wrote ML standard library. Not surprisingly, we can define our own kinds of exceptions. And what you do is you use the exception keyword. And then any name you want, it's traditional to capitalize them. So here, I've created an exception called my undesirable condition. You can see here a little bit lower that having introduced that new exception binding. I'll be able to raise my undesirable condition. You can also create exceptions. It carry values, the syntax is exactly like with constructors. So here's another exception, where my another exception is not an exception. It carrying a pair of ends would be. So you would be able to ride something like rays, might other exceptions of three, four. And that's a way to pass data out to whoever might be handling your exception, alright? So at this point we've seen our first piece of raise up here in head, we've defined our own exceptions. Now here's a function called my div, that takes two integers and if the denominator is zero, instead of raising whatever normal exception ML raises in this situation, we raise my undesirable condition instead. So that's really all there is to it. Now there is one other distinction I'd like to make. There's a difference between making an exception value, which is just something of type exn, and raising it. So here is a function max list which takes in a list and an exception. And, if the list is empty, it raises whatever exception was passed in. Otherwise, if the list has one element, it just returns it. Otherwise, it returns the max of the first element, and the max of the rest of the list. So it's another nested pattern matching example. But the interesting thing here is that the caller to max list passes in the exception. So max list, in fact, has type int list. Star E X N, which is the type of all exceptions, arrow int. because if it doesn't return, it will return in int. if it raises an exception who cares what the return type is. So, here I have a call to max list, where I pass in the list three comma four comma five and pass in this exception. Now this is not going to cause an exception to be raised, it's just an exception value. And since in this case max list won't call use arrays with the exception no exception occurs. So if I run this code w will simply end up being bound to five, the maximum element in the list. Alright? So the last thing I want to show you with exceptions, is how to handle them. This is what a lot of languages call catching an exception. So anywhere you have, and there's a new form of expression I just haven't shown you before. Anywhere you have an expression e1, you can then write handle, some exception name. It's actually a pattern. Some, exception thing. And then some e2. And what this is going to do is if E1 evaluates normally, then the rest is irrelevant. But if E1 raises the exception, listed here. Then we'll evaluate, we'll catch that exception. We'll evaluate E2 instead. If this is not the same exception that E1 throws then we are not handling it. And it continues, the result of the entire thing is that the same exception is raised. So here is a perfectly reasonable example of a handle expression. But since the thing before the handle does not raise an exception, this just evaluates the five. The result of this entire thing is just going to be five. Alright. On the other hand. If we had this code here, where we pass max list, the empty list, then indeed max list is going to end up evaluating, raising, my undesirable condition, so we will handle that exception, and the result z, will end up being bound to 42. This final example which is commented out here, this, if we evaluate it, will in fact raise the exception, so why we'll never end up being pound to anything and since we don't have a handle expression here, the evaluation of our program would stop and so that is why I have it commented out, and so we can see all these quickly, if we come over here and just use this file . We will see that I am right. That w and x are both bound to five, and z is bound to 42. And no exceptions were raised. Because the only one that happened, which was up when we evaluated the expression for x, we handled and decided to evaluate the expression to 42 instead. Okay so, let's switch back to the slides and see whats going on in general. We have a new kind of binding I had not shown you before. This is an exception binding, this is how you introduce a new kind of an exception. We have a new keyword I hadn't shown you before, raise, this is how you raise or throw an exception. And we have another new expression form for handling or catching exceptions. Where we evaluate the expression to the left of the keyword handle, if that does not raise an exception then that's our answer. If it does raise an exception and that exception matches the one we have there, then we evaluate E2, otherwise we continue to raise the exception. So, it turns out that exceptions are a lot like data type constructors, that there is this built in type EXN. Over here in the code you'll notice that max list does have type int list star EXN, error int, alright? So when you add a new kind of exception, you're really just adding a new constructor of type EXN. So EXN is just a normal type, which is why we can pass values of type EXN, like we did, into Maxlist. It's not too common to do this. But it's useful. It does let your caller choose what exception you raise. Which seems like a potentially useful thing to do. And it turns out that handle expressions are more general than I've been showing you here. You, in fact, can use pattern matching as deep as you want on those things of type EXN. And you can even have multiple branches separated, by the pipe character. Okay, but nonetheless I've shown you enough basics. You'll use exceptions just a little bit on your homework to make sure you understand how they work and how they can be used. And now you know how they work.