Enter Your Email Address to Watch This Lesson

Your link to unlock this lesson will be sent to this email address.

Unlock this lesson and all 985 of the free egghead.io lessons, plus get JavaScript content delivered directly to your inbox!



Existing egghead members will not see this. Sign in.

Create linear data flow with container style types (Box)

5:04 JavaScript lesson by

We'll examine how to unnest function calls, capture assignment, and create a linear data flow with a type we call Box. This is our introduction to working with the various container-style types.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

We'll examine how to unnest function calls, capture assignment, and create a linear data flow with a type we call Box. This is our introduction to working with the various container-style types.

Avatar
robert

I'm sure there is valuable content on this video, but the "Frisby" voice / character makes it unwatchable. I like egghead because it doesn't waste my time. What's this?

Avatar
Jason

Agreed, I made it like 10 seconds in and couldn't take it anymore :( The talking is WAY too fast to try and comprehend what is being said. And, it's frankly really annoying.

In reply to robert
Avatar
Wayne

I really wanted to watch this, but it sounds too fast.

Avatar
santiago

I was very excited to learn about functional programming when I got the e-mail. But the content and voice is so bad and mumbled that it's very hard to comprehend. Also, I don't understand what's the context of a bear and two bunnies. Please, Please make this understandable.

In reply to egghead.io
Avatar

I can kind of almost watch this if i change playback speed to .8

Avatar
Thomas

This is exhausting. It is very difficult to stay concentrated on the topic with that high pitched voice (and I used actually the minimum speed available 0.8) - I had to give up at the 2nd sequence for a break.
Still trying to figure out what's the motivation behind that nonsense.

Avatar
Mike

Unwatchable. Very disappointing.

Avatar
James

I agree that it was unexpected, but after watching for awhile, I didn't mind it as much. In fact, I like the Q+A part at the end. I appreciate that the author is experimenting with a different approach.

In reply to Jason
Avatar
Rafael

If you can go past the strange voices, the content of this course is gold! Take this first video, for example: it's genius!

Avatar
LukePammant

I'm also disappointed by this release :( This was one of the reasons I bought the holiday subscription and I can hardly watch it with that high pitched voice. It also seems like the videos start out of no where with no context as if it's missing a video.

--EDIT: I went ahead and watched the videos - the content is great albeit distracting at parts. Admittedly my initial reaction may have been too soon.

Avatar
Alex

I don't usually comment, but just to put it out there in contrast to some negative reviews:
I actually enjoyed the video. The style is interesting and the content is easy to consume. Thank you!

In reply to robert
Avatar
Ian Hofmann-Hicks

Been waiting for this for sooo long it seems.
Thanks so much for getting these out, binge watched the first half and I gotta say, this is a wonderful continuation of the Professor Frisby series!!
So much good information in there, I would have probably finished in one day, but had to open up node and try this magic out for myself!!

The imperative to declarative refactorings are my absolute favs.

Avatar
EBIA

valuable & interesting content with terrible audio, could not watch it to the end,.. would be great, if you forgo the comic figures,..

In reply to egghead.io
Avatar
Billing

Great content but the idea with unnatural, fast, high pitched voice is just terrible :(

Avatar
Andy Stoica

I thought the computer has gone crazy, then I saw the other coments :) Weird experience, good content.

Avatar
Joseph

Agreed, voice is a little distracting but I got used to it. The conversational style is actually kind of nice

In reply to Alex
Avatar
Joseph

I'd like to know his workflow for this exercise for when i'm on just my laptop without screens. Obviously VIM, possibly TMUX... or some weirdness with VIM i don't know... Node, likely with autocompile script on save?

Avatar
David O'Halloran

Great Content, no issue with the style

Avatar
Steve

I found the sped up voice difficult to understand; by using the speed control on the bottom left and turning to the slowest speed: 0.8 it was possible to follow what was being said.

Avatar
Aladeen

I'm sure there is valuable content on this video, but the "Frisby" voice / character makes it unwatchable. I like egghead because it doesn't waste my time. What's this?

I totally agree with you, the voices have ruined this course it's impossible to follow with the instructor :'(

In reply to robert
Avatar
Steve Lee

What is this magic "inspect" thing? How does it get called?

Avatar
Steve Lee

PS, also OK with style. Thought Edge was messing with playback speed for a second. :)

Avatar
Vamshi

Excellent video!

Avatar
George

What is up with the audio. Plz fix..

Avatar
Tyler

Audio ruins this. Please re-release in a normal format. Cute is not helpful...

Avatar
Jon

I appreciate the desire to do something fun, but the squeaky voice is just too distracting and annoying. Shame, as the content of this course was something I was really looking forward to.

Avatar
Nut

Voice absolutely destroys this video series. Please re-voice this correctly, otherwise not really watchable.

In reply to Jason
Avatar
Flavio

+1 to changing the voice

In reply to egghead.io
Avatar
Ainu Jorge

Totally insane! This is pure gold. C'mon guys, enjoy the magic! Too much speed? give it a try with 1.5x, pure adrenaline.

Avatar
Brian Lonsdorf

Hi! I made these videos.

I know lots of people are requesting changes, but there will not be any for two reasons:

1) I don't have the original footage anymore (the videos are huge so i delete them afterward)
2) I really wanted to make this project and it turned out just how i wanted it. There's nothing to "fix".

My choices here were against Egghead's style and recommendations and should not reflect on them at all.

If you are interested in learning the content and you feel that's not possible with this series, I am adding it as chapters to https://github.com/MostlyAdequate/mostly-adequate-guide and there are other instructors here teaching FP in different ways.

Thanks for your feedback and I'm truly sorry you dislike what I've made.

-Brian

Avatar
Darion Welch

Haters gonna hate, learners gonna learn.

Avatar
Aurélien

I love your work. Thanks a lot for the time you spent on this

In reply to Brian Lonsdorf
Avatar
Noah Rawlins

What is the value added by using a distracting voice that is basically unintelligible at normal speed or higher and cutaways to animated characters? Seems like effort that could have been spent on actual content. I was looking forward to this, but it's a real effort to listen to it.

Avatar
ray

Thanks for the effort of putting these awesome stuff up and make it easier for newcomers, after almost watching all your videos, still not bad to come back and revisit. :)

In reply to Brian Lonsdorf
Avatar
Andres

Thanks for your effort of making this hard topics enjoyable. For me it is a bit difficult to digest all the infomation with the speed on this video as english is my second lenguage but I think it is not impossible. Those chapters will come in handy as I watch your videos

In reply to Brian Lonsdorf
Avatar
marcelo

i've watched all videos now, and i find a little bit distracting the video format but nothing too bad...

about the content of the series, is the box concept a little bit what Rxjs does under the hood? (not the iterator observable pattern, but how it chains methods )

Avatar
Brian Lonsdorf

Yes! RXJS is founded upon these exact ideas. Eric Meijer (haskeller/author of famous white papers/legend) brought the ideas from Conal Elliot's FRP stuff to C# and JS.

All holding the monadic spec/theory, the implementation is free to be as performant as it wants without losing composability.

In reply to marcelo
Avatar
Georg

A for sure, must to watch lesson, throw to the trash.
If possible, upload it again with normal voice and try to avoid this kind of thing on the future!

Avatar
Kristian Mørch

Best ever 👍 First time I have smiled so much while learning.

In reply to Brian Lonsdorf
Avatar
Pat

Wow. Fix the voice! This is unwatchable!

Avatar
Brandon R. Howard

Great video. I really like the concept and the author does a great job explaining. The fast speed and animations are a bonus! 😁

Avatar
Belen

I've downloaded this app called Boom 2 that lets me change the pitch. After that and slowing down the video to 0.8 I could finally watch it :)

Avatar
MetaSean

While the voice does occasionally make it heard to understand what's actually being said, I really like the format! (Granted, I tend to watch most tech videos at 1.5-2.25x so I may be a bit biased.) I'm much more bothered by Right always being to the left of Left, likewise, Left is always to the right of Right.

That said, and to second Steve Lee's question:

What is this magic "inspect" thing? How does it get called?

In reply to Brian Lonsdorf
Avatar
Brian Lonsdorf

Hey there!

I didn't realize inspect() was a bit esoteric. The idea is that it is called implicitly by Node's console.log() to give you a way to show your own data types.

It doesn't work in the browser though. For that, I'd use toString() and call console.log(String(x))

Hope that helps!

In reply to MetaSean
Avatar
Luis

WTH is up with that voice? It feels like a 3 year old is teaching me javascript.

Avatar
Brady

Whereas other videos are painstakingly edited to remove all unproductive spans of time, this video cut to a clay animation. At which point I felt compelled to quit. Not to mention the voiceover. Oh that voiceover. It sounds like something between Alvin and the chipmunks, and Eric from south park. I feel like I've been unwittingly tricked into test screening someone's first attempt at children's animation.

I expect this course to be redone correctly- like the others.

Avatar
Mike

I am rewatching this series and still love it.

Avatar
Daniel

One solution is to download the file, open it in VLC and press [

Avatar
Juan Maia

what is this voice? I mean, what's the point?! geez

Avatar
Pierre

To get a normal voice:
- Download the vidz
- Open in VLC
- Command comma for the preferences
- Show all
- Audio
- Untick "Enable time stretching audio"
- Save
- Window > Audio effect
- Enable equalizer
- Play
- Command minus to reduce the speed to 0.67%
- True voice activated :)

Enjoy

Avatar
Wayne

That's what I've been wondering. :)

In reply to Steve Lee
Avatar
Mark

Someone needs to fix the transcript. The code is wrong in many places. Some proofreading is in order.

Avatar
Ignacio

wow. clever idea. but please don't.

What are we looking at here? We have nextCharForNumberString. What this does is take a string down here like our number. We could have spaces, comes with user input or whatever. We're going to trim it, parseInt, add one number to it, and get the fromCharCode from String.

const nextCharForNumberString = str => {
  const trimmed = str.trim()
  const number = parseInt(trimmed)
  const nextNumber = number + 1
  return String.fromCharCode(nextNumber)
}

const result = nextCharForNumberString(' 64 ')

console.log(result)

The point of this function is not the actual functionality. If you look at each of these lines, they're doing different things.

We have a method call here. str.trim()

We have a function call here, parseInt(trimmed)

an operator, number + 1

and then a qualified class function here. String.fromCharCode(nextNumber)

We want to unify it all and compose it in one linear work flow instead of separate lines with lots of assignment and state as we go along.

How can we do this? Let's run it to see what the output is. It's the capital A. That's because 64 turns into 65, then we get the fromCharCode of that which is the capital A.

If we comment this out, and let's rewrite this in a new way, one thing we can do is say we'll try to compose this up in one big expression functionality. We'll call trim which is the method. The next thing that happens is we parse the int. The next thing that happens is we add a one. We call String.fromCharCode around it.

// const nextCharForNumberString = str => {
//   const trimmed = str.trim()
//   const number = parseInt(trimmed)
//   const nextNumber = number + 1
//   return String.fromCharCode(nextNumber)
// }

const nextCharForNumberString = str => 
  String.fromCharCode(parseInt(str.trim()) + 1)

This is very confusing. It will still work. Let's give it a shot. There it does. It's got a capital A there. If we look at the control flow here, it's totally bogus. It's one expression, very clean, but hard to follow. It jumps all around here, trimming, parsing, and adding one over there.

Let's borrow a trick from our friend array. The first thing we can do is put our string in a box, and that's it. We put the string in a box. It's just an array with one value.

const nextCharForNumberString = str => 
  [str]

Now, we can map our s and trim it. We can keep chaining these maps. We can turn this s into a number by calling parseInt on it. What do we have? We have an i here for an int. We can say i + 1.

Finally, we'll say i is String.fromCharCode. We turn that back into a number.

const nextCharForNumberString = str => 
  [str]
  .map(s => s.trim())
  .map(s => parseInt(s))
  .map(i => i + 1)
  .map(i => String.fromCharCode(i))

This is very, very nice letter rather. If we run this, we should have A in a box. Indeed, we do. We have A in the array. I'm calling it a box here.

Terminal Results

[`A`]

What happened here? We've captured each assignment in a very minimal context. s cannot be used outside of this little error function in map. Despite calling it the same variable here, we can change this to r or whatever we want to call it.

The point is, each expression has its own state completely contained. We can break up our work flow, and go top to bottom, doing one thing at a time, composing together. That's key. map is composition, because it takes input to output and passes it along to the next map. We're composing this way.

const nextCharForNumberString = str => 
  [str]
  .map(s => s.trim())
  .map(s => parseInt(s))
  .map(i => i + 1)
  .map(i => String.fromCharCode(i))

Let's see what else we can do here. Instead of an array with a bunch of maps on it, why don't we make this a little bit more formal? I'm going to make a type called Box. Box is going to take an x here. We'll define a map of our own that works exactly the same way.

We'll take some function f. It will return a Box of f of x. It's returning a Box of F of X, so we can keep chaining along. If we didn't return the Box, we wouldn't be able to call .map, .map again and again.

const Box = x => 
({
  map: f => Box(f(x))
})

We're running our function with f on x, and then putting it back in a Box. This should be exactly the same thing. We could put this in a Box and have this work flow happen here.

const nextCharForNumberString = str => 
  Box[str]
  .map(s => s.trim())
  .map(s => parseInt(s))
  .map(i => i + 1)
  .map(i => String.fromCharCode(i))

Let's do one more thing, though. Because it's hard to look at this data structure in the output, let's give it a little inspect. This is a nice little trick that allows us to, when we call console.log, we actually see what the data structure is holding and not just the data structure itself.

It will format the output and our little template literal here. We need a little comma.

const Box = x => 
({
  map: f => Box(f(x)),
  inspect: () => 'Box($(x))'
})

Let's give it a go and see if we have ourselves a Box of A. Indeed, we do, a Box of A. That's very good.

Terminal Results

Box(A)

With this, we can start composing along. We've unified both method calls, function calls, operators, and qualified. We can instead of parseInt here. We can do a constructor for new Number, and so on and so forth.

const nextCharForNumberString = str => 
  Box[str]
  .map(s => s.trim())
  .map(s => new Number(r))
  .map(i => i + 1)
  .map(i => String.fromCharCode(i))

If we want to add more functions, we can go ahead and map along, and say maybe i, or what is this? It's a fromCharCode now. It's a c here. We'll say c.toLowerCase(). Now, we have a lower case a in a box.

const nextCharForNumberString = str => 
  Box[str]
  .map(s => s.trim())
  .map(s => new Number(r))
  .map(i => i + 1)
  .map(i => String.fromCharCode(i))
  .map(c => c.toLowerCase())

What to do with this Box? We didn't actually want it in our Box. We wanted it outside of the Box. We wanted our normal character here. Let's add one more function to Box. We'll call it fold. What this will do is remove it from the Box as we run the functions just like map, except it doesn't put it back in the Box.

const Box = x => 
({
  map: f => Box(f(x)),
  fold: f => f(x),
  inspect: () => 'Box($(x))'
})

Down here on our last statement, we can call fold instead of map, which will fold it out. It will remove it from the Box as it runs this function.

const nextCharForNumberString = str => 
  Box[str]
  .map(s => s.trim())
  .map(s => new Number(r))
  .map(i => i + 1)
  .map(i => String.fromCharCode(i))
  .fold(c => c.toLowerCase())

Does anybody have any questions?

"I thought map was supposed to loop over stuff?"

Well map isn't so much about iteration as we'll see. It has more to do with composition within a context. In this case, Box is our context. We're going to be using a lot of these container-y types to capture different behaviors as we compose. It allows us to compose in different ways.

"Isn't that the identity functor?"

Indeed, it is the identity functor, but we're going to call it Box for now so we don't scare everyone.

"That just can't be efficient."

Well... As far as efficiency is concerned, because this is composition in disguise, we confuse these together. As it stands, you'd be hard-pressed to tell any difference at all even in the large-scale application doing all these things unless you are making a pacemaker, doing a bench mark of 10,000 or something like that.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?