Use chain for composable error handling with nested Eithers

Brian Lonsdorf
InstructorBrian Lonsdorf

Share this video with your friends

Send Tweet
Published 5 years ago
Updated a year ago

We refactor a function that uses try/catch to a single composed expression using Either. We then introduce the chain function to deal with nested Eithers resulting from two try/catch calls.

[00:00] Let's look at another example of using Either. We have our previous definitions here, right and left and front nodable. I've written a little get port function we're going to refactor using FS. What does this do? It's going to read the file, config.json, which I've prepared here, config.json. It's got port 888. It's going to parse it, and then grab the port.

[00:18] If anything goes wrong we'll return 3,000 as a default. If I run this, we should have ourselves an 888. There we are. If we mess up the file name we will get the 3,000 default just like that.

[00:30] The first thing we need to do here is let's go ahead and copy this as a template, and grab our first line. You'll notice it's in a try catch. We're going to use Either to get rid of this try catch. Let's go ahead and write one once and for all with a little helper method here. We'll call it try catch.

[00:45] We'll take a function and say if the function succeeds, we will put it in a right. If it fails in the catch case, we'll throw it in a left here, return the left of e. That is all there is to it. This is the one and one time only we'll write try catch. Oh, I forgot the T here.

[01:04] If it returns, we'll know if it's a right or a left. We don't have to check if it's an error or not, or do another try/catch somewhere else, because we have a composable type that will do the right thing when mapped and folded.

[01:14] Let's go ahead and use this try catch down here to wrap our read file. That way it won't explode if it doesn't find the file. Then we can map over that if it succeeds it will run this map. If it returns our left, remember, it will not run map at all. We can count on json parse working here because we have our contents.

[01:30] Then we will fold it down. If we have an error we'll return our 3,000 default. If we get our parsed config here we'll just do port on that. This should work just fine. Let's go ahead and comment out the old one, and try this out and take it for a whirl.

[01:48] There we are, 888. Good times. If we get rid of this I or G or something and we run it again, we get 3,000 just like we wanted. But there's one thing going on here that the old one did. This one doesn't. If you look up here it's all in a try catch block. If we go ahead and remove the port 888 and we try to parse this, what's going to happen is this parse is going to explode in it.

[02:03] Then we're not going to have a value. Let's go ahead and give this a shot. It will blow up just like we expected. Unexpected end of json input. What we have to do here is put another try catch just like that. That will capture the error.

[02:18] However this map is going to open up our right here. Say we have a right of some contents. It's going to pass in the contents. Then try catch returns another Either. We have a right of either a left of some error, or we have a right of another right.

[02:34] Just like box in the other example, we'll have to fold twice. This gets really, really confusing. What we're going to do is write a new function that's just like map. We're going to call it chain. That will return one right.

[02:46] Let's head up and define chain. Chain is just like map, except we're not going to box it back up just like we wanted. That way we'll end up with one right or left after the end of this. Then similarly with our left side, we want left to act like a left. Left just ignores everything. That's all we need to do is return itself back.

[03:04] Don't worry if you're getting confused about all these definitions. There's only going to be a handful. It's more about how we use them in context. We'll develop an intuition for these things.

[03:11] Let's go ahead and use this chain here. It says, "If we're going to return another Either, we are going to use chain instead of map." Let's go ahead and run this. There we are. We get 3,000 because our config is malformed.

[03:23] If we remove this part, we still get 3,000. If we go fix our config.json back to where it was, we will get our 888 just like that. Very good. Is there any questions?

[03:31] Isn't chaining and folding the same thing sometimes?

[03:34] Right. Chain is defined just like boxes fold was. The idea is that here, fold is going to capture the idea of removing a value from its context -- taking it out of the box, whether it's a right or a left or a box itself.

[03:47] Chain expects you to run a function and return another one. We'll keep that convention and intuition as we go along. They are two very functions even though they might have the same definitions sometimes.

Brian Lonsdorf
Brian Lonsdorfinstructor
~ 5 years ago

I'm not sure I understand your question. Can you clarify? Either is the actual monad here chain is >>=