Advanced Elm Advanced Elm

Pipeline types & Decode.map3

Check out a free preview of the full Advanced Elm course:
The "Pipeline types & Decode.map3" Lesson is part of the full, Advanced Elm course featured in this preview video. Here's what you'd learn in this lesson:

Richard shows how the Decode Pipeline types interact with the types of the Decoder primitives using Decode.map3.

Get Unlimited Access Now

Transcript from the "Pipeline types & Decode.map3" Lesson

[00:00:00]
>> Richard Feldman: So we'll talk about a few things here. First we're gonna talk about pipeline types. We're gonna talk about Decode.andThen, then decoderizing which is a term I made up and finally intermediate representations. Okay, let's start with pipeline types. And before we get to pipeline types, we're actually gonna build our way up to that by talking about just plain old decoding types, the plain old decoder primitives themselves that are gonna be used in pipeline.

[00:00:25] So let's say we have a type alias called Instructor, and it's got name, which is a string, courses, which is an Int, and isTeaching, which is a Bool. So let's say Richard, num_courses, 2 and active, these are the things that we're going to be decoding from. So that's the JSON on the right, and then on the left, we have the type alias that we're going to decode into, okay, so because we've defined a record type alias, anytime we do that, we get this function for free that is the same name as the type alias.

[00:00:51] So if I put Instructor with a capital I in record, just because I've defined this type alias, it's going to say, cool, that is a function from String to Int to Bool to Instructor. Because this has three fields, they are defined String, Int, Bool, in that order, so that’s where the arguments come from.

[00:01:07] And if I provide all these, it’s going to populate each of these fields in one of these records and return and instructor for me. Okay, I can decode a single field from any JSON object by using decode.field. So the way this decoder works is it takes a string for the name of the field then it takes a decoder for the expected value associated with that field, and then it gives me back a decoder which will decode that value from the object.

[00:01:34] Important to note how decode.field works in isolation. If all I do is I run this decoder on a JSON object, all this decoder is going to do is it's gonna say I don't care what's on that object. If that feels on there and its got that value, we're good, decoding succeeded.

[00:01:53] It does not care at all the rest of the values. It doesn't care about the rest of the fields. It just cares does it have at least that one field and is it the type that I expect. If so, great, we decoded and we succeeded, this is important to note because when we start putting these things together and we start using multiple decode fields, it's important to remember that.

[00:02:13] At no point are we saying this is the exact shape of that JSON object. So essentially it works kind of like open records in the sense of saying I expect that at least that field is present, but there may be others, and if so, I don't really care.

[00:02:25] Okay, so let's decode that field. So we've got our instructor, we've got decode.field. And we can put these together with decode.map3. So let's say we take a look at this function and we see that it takes three decoders, there's also a map two which takes two decoders and map which takes one decoder.

[00:02:49] And it takes a function from a to b to c, where a is the first Decoder's type, b is the second one's type, and c is the third one's type, and that function is going to take a to b to c and return a val, and ultimately this gives us a decoder val.

[00:03:02] So using all the ingredients that we have here on the screen, we can see that if we want to make a decoder that's going to decode some fields into an instructor and end up with a decoder instructor. This is one way we can do that. We can say Decode.map3.

[00:03:18] Pass or function right here which is string, int, to bool. Then pass a decoder string, a decoder int to the decoder bool which we can use Decode.field to get as the corresponding fields on a JSON object. And then, by putting all these together, we say Decode.map3, Instructor, field name string, field courses int, field active bool, and what map3 is going to do is it's going to run them one at a time.

[00:03:46] It's going to run this one and say, okay, did that succeed? And it says, all right, the first Decoder. If it's a field name and there is in fact a field on that JSON object called name which happens to be a string. Then it says, great, that decoder succeeded, next one.

[00:04:00] Run it again, that one succeeded. Run it again, run the third one, that succeeded. Now, if all three of them succeeded, then it's gonna say, great, I now have three values that I can pass to this function right here. And since what we provided for this function was instructor, it's gonna say okay.

[00:04:16] Take that first one, passes the first argument, second argument, there was a third argument which is the same name. That string is gonna be the first argument which is what we want. Second is gonna be int which is also what we want. And the third one is gonna be a bool which is also what we want.

[00:04:28] And finally we will end up having successfully decoded this instructor. So this is how to do it using map three.