Advanced Elm

Intermediate Representations & Review

Richard Feldman

Richard Feldman

Vendr, Inc.
Advanced Elm

Check out a free preview of the full Advanced Elm course

The "Intermediate Representations & Review" Lesson is part of the full, Advanced Elm course featured in this preview video. Here's what you'd learn in this lesson:

Richard uses the example application as a reference while explaining intermediate representations as for the idea of using internals only for the purpose of creating a decoder, not exposing it to the outside world as an intermediate step, then using Decode.map to convert to the one that the world sees.

Preview
Close

Transcript from the "Intermediate Representations & Review" Lesson

[00:00:00]
>> Richard Feldman: Decode.map is something we're using in quite a few places in the code base. So one example of it is the one that we saw earlier, where we needed to translate the body into a full body on the article. So this is an example of using decode.map to essentially wrap a value that we're getting as one of our fields in some other type.

[00:00:19]
So the purpose of this was that we have two notions of article, we have article full and we have article preview. And in this case, when we're decoding the preview, we wanna hard code it and say yeah, we're not gonna look for any additional info on there, it's just a preview.

[00:00:31]
There's no body associated with it, so don't worry about it. And in this case, we want to say we have an article full, and we use decode.map to say not only do I want to decode the body, which is the same as body decoder. But once that's done, I want to, if it's successful, transform that success value by wrapping it in this full value right here.

[00:00:52]
And full is defined like this, so it's a function that takes a body and returns a full value. Okay, so that's one example. Another pretty common example we can see in this right here. So here we have a comment. Comment, like so many other types in our program, is opaque and it looks like this.

[00:01:17]
This is a pretty common strategy that I like to use for representing opaque types while still getting access to the nice record constructor for decoding purposes. So I'll define alias called internals, that represents the record that I can work with internally to this module. I don't ever expose it to the outside world, and then I can use it for JSON decoding.

[00:01:36]
So I have comment, which has one variant, and its sole variant has one argument, which is internals. And as previously discussed, in terms of run time representation, that means that because it's a single variant with a single value inside of it. Elm's going to unbox this and at run time, this is just going to be as if I'd used a record, plain with no wrapper around it.

[00:01:59]
But for compile side purposes, I do actually need to specify that wrapping. So when I'm using this internal's decoder, I'm essentially writing as if I had used this as my fundamental data type. I'm gonna decode into this. It's gonna follow the same pathway we saw on the slides, we're gonna require this, which is gonna be the first argument to that function.

[00:02:19]
This will be the second, this will be the third, this will be the fourth. And then once those are done, we know now after having gone through those slides, this expression will evaluate to a decoder internals.
>> Richard Feldman: But that's not what we want. What we want is a decoder comment.

[00:02:37]
And in order to map it to a comment, we can just take this expression right here and say once we're done decoding into internals, just wrap it in a comment, no problem. And that's all there is to it. This is a pretty common way of translating, sort of getting the best of both worlds.

[00:02:56]
Getting to use the record constructor internally for convenience while still exposing an opaque type to the outside world for a decoder. So to recap, we talked about pipeline types and how those work, talked about Decode.andThen. We talked about decoderizing, so that's with the ISO 8601, we sort of decoderize that from a result into a decoder by using decode.andThen.

[00:03:19]
And finally, we talked about intermediate representations, so the idea of using internals only for the purpose of creating a decoder. Not exposing it to the outside world, and just using that as an intermediate step. And then using decode.map to convert from that intermediate representation into the one that the outside world actually sees.

[00:03:35]
One more note on intermediate representations is that if you want, you can take that a few steps further. And use it with Decode.andThen or something else to decode into some record that kind of has no relation to what the internal, the final representations going to be. But which just get into the record so you can work with it more nicely in your Elm logic.

[00:03:52]
If you have some complicated andThen code or something like that to work on.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now