Construct a Stateful Monad

Share this video with your friends

Social Share Links

Send Tweet
Published 6 years ago
Updated 5 years ago

We define the State datatype and take a peek into its inner working. By manually constructing an instance, we’ll start to get a feel on how the type separates state management from our stateful computations. As State depends on a Pair type, we get to know how each portion can be extracted through the fst and snd Pair instance methods.

Instructor: [00:00] State" is defined as a product type with a fixed type state "s" on the left and a variable type resultant "a" on the right. Let's bring in "State" so we can construct one of these and attempt to put some meaning to all these words.

[00:13] We first pull in the "State" constructor by requiring it from an ADT library named "crocks." With our constructor in scope, let's create an instance of "State" which we'll call "m" for now. We define "m" to be a state with a number type for the state portion and a string type for the resultant.

[00:31] To construct a state, we need to call the constructor, passing it a function, but not just any old function will do. It needs to be in a specialized form. The function must accept a value of the fixed state and return a pair of values with the resultant in the first lot and the state in the second.

[00:48] Since we have to return a pair, we'll bring in its constructor as well, which is also available in "crocks" simply as "Pair." Now we have everything we need to construct our state. We pass a function that takes some state and returns a pair with a string of value in the first portion, and we just echo the state in the second.

[01:09] Now we can log this out to the console and see what we have. We'll pass our "m" to this log function, give it a quick save. We see we get back a "State" wrapping our function although our function did not run. That's because "State" is a real lazy bum. It's never eager to do anything unless demanded. In order to do anything, it must first have some initial state to work with.

[01:33] We can give it the number it so desires by calling this runWith method and passing it 45 for its initial state, give it a save. We see now that we get back our "Pair" with the string in the first and 45 in the second. "Pair" provides a couple of extraction methods for plucking out its values. We use this "fst" method to pull our resultant and "snd" to pull the state.

[01:57] We might as well make use of this state in a meaningful way since it's available to us and all. By meaningful, I mean let's replace this string with the result of adding 5 to any given state. We need to update our signature by replacing "String" with "Number." For brevity, let's remove the extra number and remember that "State" is parameterized by two types.

[02:19] With our change in place, let's pull the resultant and see what's cooking. With our "State" being 45, we see that our resultant is now 50. Delicious. But it doesn't stop there. We can also update the "State" portion and echo the original state of 45 in the resultant. By extracting the state, we see that it has been updated now.

[02:41] While this is great and all, as it stands now we can only increment by 5. It would be nice to be able to increment by any given value. Let's clear the board and make a couple of helpers. We'll start off with a way to update the resultant or value with a function aptly named "updateValue."

"[02:59] UpdateValue" is defined as a function that takes a number and returns a state of "Number Number" or just "Number." To implement, we first take a number "x" and return a newly constructed state that takes a "State s" and returns a "Pair" with our result in the first and our echoed state in the second.

[03:20] Let's give our new function a call, passing it a 10, and see what we get. As we hoped, we see we get back our lazy old state ready to be run.

[03:29] Let's call "runWith" on the result of our function, sticking with our 45, and disco. We get our "Pair" with 55 in the first and our "State" 45 in the second. Using "fst," we pluck the resultant from our "Pair" and get 55. Of course, "snd" will give us our state of 45.

[03:50] With the resultant updates in the bag, let's see what we can do about "State." With a little copypasta, our state updates are easy-peasy. We just need to update the name of the function to "updateState" and move our calculation to act on the state portion instead.

[04:07] Now let's call this new "updateState" function and peep the results. We see our state has been updated. Let's check the resultant in the first and verify we get our expected 45. Ladies and gentlemen, looks like we have a winner.

David
David
~ 6 years ago

Would be nice to turn off the keyboard noise. :)

Chris Frewin
Chris Frewin
~ 6 years ago

Hi Ian, great course! This stuff is blowing my mind! One thing though about the setup, for those running the code locally in just a terminal with node index.js, at least for me, I get a window is not defined error, of course since there is no browser.

For anyone else who might be getting the same error, I just removed the const log = require('./logger') and changed the log() function to console.log(), and you can follow the lesson through!

Ian Hofmann-Hicks
Ian Hofmann-Hicksinstructor
~ 6 years ago

@Chris Great point, I do have a github repo that has each lesson in a branch that will run on node w/o any modification. If that helps!!

Ian Hofmann-Hicks
Ian Hofmann-Hicksinstructor
~ 6 years ago

@David

Would be nice to turn off the keyboard noise. :)

Noted. Will take care to bring that down in future casts. Sorry about that!!

adesso
adesso
~ 6 years ago

Yeah, the clicking from the keyboard is way to loud and very annyoing.

adesso
adesso
~ 6 years ago

Andy please try to talk like in real life next time. You are not selling us something ;)

EdmundsEcho
EdmundsEcho
~ 6 years ago

Thanks Chris. I ran into the same issue. Your answer helped. - E

Matmo10
Matmo10
~ 6 years ago

A little bit of background and context at the beginning would have been nice. For a whole series on State and monads, an overview of what state and (especially) monads are in this context is pretty crucial IMO. 10 seconds in and we're already learning some specific library.

At 7 seconds in you're using (IMO) unclear notation for something we don't even know what it is yet. At 28 seconds in, that notation with :: is also very confusing, and seems to be inconsistent with that you wrote previously. It feels like you're using notation from another language or paradigm, because I failed to recognize it as a JavaScript user.

TL;DR - I'm still sitting here wondering what a Monad is.

Ian Hofmann-Hicks
Ian Hofmann-Hicksinstructor
~ 6 years ago

@Matmo10 There are a lot of resources out there surrounding Monads and the Type Notation. With this lesson I am trying to focus on how to use a State Monad to abstract away state management and unload it on the type itself. Instead or reiterating subjects that have been thoroughly covered. I really have nothing new to add to that space (Monads in JS, Hindley–Milner type signatures, etc).

For the theory portion I HIGHLY recommend @drboolean's course:

egghead-course

Also he has a wonderful book which you can find here:

gh-pages-book

One thing regarding those types, is I attempt to put in english what the siggy represents as I type, hoping that the learner may pick up syntax.

As far as proprietary, those types used in crocks use a common "open" standard for creating algebraic datatypes in javascript. So even though we are learning with crocks, a vast majority of the State datatypes in the wild will behave in the same manner (with a few exceptions of course).

I do hope you push through though, it is my hope that as the course progresses, an intuition on the purpose of this datatype starts to form.

Matmo10
Matmo10
~ 6 years ago

Thanks for the resources Ian, I will definitely take a look!

Csongor Széles
Csongor Széles
~ 6 years ago

Ohh, keyboard is sooo noisy! Don't use a gaming keyboard for video tuts.

Ruby Team
Ruby Team
~ 6 years ago

Sounds kinda robotic. Also, it would be helpful to explain some basic things that might take a bit to click like 'fst' is for 'first' and 'snd' is for second!

Ian Hofmann-Hicks
Ian Hofmann-Hicksinstructor
~ 6 years ago

Sounds kinda robotic. Also, it would be helpful to explain some basic things that might take a bit to click like 'fst' is for 'first' and 'snd' is for second!

Thanks for the feedback. Sorry about the fst and snd I (wrongly) assumed that saying the values at 1:43 with their respective names first and second would have made the connection enough for it to be put into context at 1:52 to what they would be for the portion of the State (Resultant/State).

As very soon in the course we drop directly working with the Pair in favor of execWith and evalWith, I thought it may obfuscate and take away from the structure of the State ADT. Will definitely reevaluate how much I should just breeze over in the future!

Thanks again for taking the time to provide feedback. Always appreciated.

Joost Galama
Joost Galama
~ 6 years ago

I have to agree with Ruby Team and Adesso. Both the voicing and the clicking keep me from listening beyond a few minutes.

Dean
Dean
~ 5 years ago

I think the voicing is engaging and much better than the usual monotone. Good job on the course.

Markdown supported.
Become a member to join the discussionEnroll Today