Advanced Elm Advanced Elm

Extensible Data Solution

Check out a free preview of the full Advanced Elm course:
The "Extensible Data Solution" Lesson is part of the full, Advanced Elm course featured in this preview video. Here's what you'd learn in this lesson:

Richard live-codes the solution to the Extensible Data exercise.

Get Unlimited Access Now

Transcript from the "Extensible Data Solution" Lesson

[00:00:00]
>> Richard: Okay, let's go through the solutions. All right, so first one we have TODO make this return the article's body. So to do that, we're going need to pattern match on it to extract it. So if we look back at the type of article, we see the article has two, sorry, it has one variant which has two pieces of data inside it.

[00:00:19] So one is internals and the other is the extra info. So we don't really care about the internals, so we're just gonna underscore that out of the way. What we do care about in this particular case, is the extra stuff because the extra stuff in this case, is full and full is what holds onto our body.

[00:00:34] Now, because this is an inline pattern match, we can grab full. And also, at the same time, pattern match out the body, or as I'm gonna call it bod, to avoid a naming collision with the body itself. [COUGH] And at that point, I've now successfully extracted it and I can just return it.

[00:00:50] So this, a little bit of pattern matching, followed by an extremely straightforward implementation with just returning the thing that we pattern matched out. So now if I compile this, I should theoretically get one fewer compile error. And sure enough, I'm now down to two errors. The next one is upgrading from a preview to a full one.

[00:01:07] So here we've got the body as an argument, so we'll call that bod again, so nothing else to do there. And then we've got article preview. So again we're going to pattern match on it, and once again we don't really care about the internals. But this case, we don't wanna give it an underscore for a name because if we do, we don't be able to use it when we're constructing the full one later.

[00:01:23] So I'm going to say internals and just give it a name so that I can use it in a moment. However, in this case we have the preview as the other piece of data that we could pattern match on, but now, we actually don't care about that. So I could put that as an underscore.

[00:01:39] But I'm actually just gonna put Preview here to do an explicit pattern match. Just so that I can remind my future self that it's not an underscore because I'm choosing not to use it. It's a preview, which is to say it is actually useless. There is no value I could possibly get out of this thing, so I'm just gonna put it in the pattern match, just to remind myself as a form of documentation.

[00:01:59] Okay, so we got that now, and I want to convert to an Article Full. How do I do that? Well at this point, I want to construct one of these articles and how can I do that? The answer is I'm going to once again say Article Internals extraInfo.

[00:02:15] And to build this extraInfo, I'm going to say Article internals, and I'm gonna build the extraInfo by using the bod that I have and passing it to full as a constructor. So now, I have constructed a brand new article which has the same internals as before, which is completely discarding this preview and replacing it with a new instance of Full that has the body that we are provided.

[00:02:42] And if we go to compile that, we're now down to one error. And last but not least, we're going to decode our way into having a body. So here we've got the custom internals decoder, which is going to give us back the decoder necessary to extract the internals part of that.

[00:02:58] We're calling decode.succeed on article itself. As a quicker side here, I know that some folks in the workshop who might have done this in the past have had more or less experience with JSON decoders. So if you're feeling a little bit stuck at this part, that's okay we're gonna get into this in more detail later.

[00:03:15] But I did wanna go over this in the context of how do you actually do this from one of these extensible custom types. So we're going to succeed directly into the article which is to say we're going to pass these two things as arguments directly to that article variance itself.

[00:03:32] So the first one is internals which is why we have that custom internal z code there. The second one is body, but if I just do body.decoder here like the comments suggest that I do, which is of type decoder body. I'm just gonna turn that into a comment so I can remind myself.

[00:03:49] [COUGH] Oops, that was a mistake. Let's put that up there. Nope, fourth time's the charm, there we go. Okay, so that's what I've got in there. Let's see if that compiles. No, it doesn't. Well, part of the reason is because I didn't spell it right, decoder.
>> Richard: Okay, type mismatch, so the problem is that I have decoded the body, but what we actually need is full because that's what goes in that second slot.

[00:04:16] Body is not the type of extraInfo that we're going to need if we wanna have an Article Full here. I could say I'm gonna return the article body, but that's not what we want. What we want is an Article Full. An article body is not useful because everything in this API is in terms of either full or preview.

[00:04:30] So if I decode my way into an article body that's not really doing anybody any favors. So how can I do that? Well, essentially all I wanna do is I want this decoder right here not to be a body decoder, but rather to be a full decoder. And the way I can do that is by using Decode.map.

[00:04:46] So Decode.map takes a function which will convert one decoder from another by wrapping its internals or transforming its internals by a function. So I'm gonna say decode.map Full Body.decoder, which means that since body.decoder is a decoder body, that's going to translate it into a decoder Full. Because the function that I'm providing decode.map is something that goes from a body to a full.

[00:05:12] So by doing this, I have now given, I'm still requiring the same field. I'm still reading the same body out of the json, but once I've got it, I'm now converting it to a full, I'm upgrading it.