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 960 of the free egghead.io lessons, plus get JavaScript content delivered directly to your inbox!



Existing egghead members will not see this. Sign in.

A collection of Either examples compared to imperative code

2:05 JavaScript lesson by

A tour of simple functions rewritten as composed expressions using Either set to 8 byte music and colorful flying blocks


egghead.io comment guidelines

Avatar
egghead.io

A tour of simple functions rewritten as composed expressions using Either set to 8 byte music and colorful flying blocks

Avatar
David

Holy crap, the one at 1:30, with the wrap and fs.readfilesync is still just blowing my mind. I don't know if it's better, but it's definitely harder for me to reason about that the moment. I think have all the references to what tryCatch is, etc, may help with context. Or just practice, doing, and refactoring real code to get the hang of it.

Regardless, loving this course so far!

In reply to egghead.io
Avatar
Nick Ostrovsky

Wrap has an error. Should be something like preview => { ...example, preview }, not ex => ....

Avatar
Alexander

Yes, wondered about that for a bit too. Although I'd describe it like this: the fold on unpacking the read 'preview' from the file should clone example and then assign the new preview prop.

.fold(() => example,
        preview => Object.assign({ preview }, example))

I would maybe even Object.assign({}, example, { preview }) to be nice and obvious.

In reply to Nick Ostrovsky
Avatar
Brian Lonsdorf

Yep! Sorry about the mistake there. This is what I should have had

In reply to Alexander
Avatar
Egghead

Hi,

In second example (getPrefs method), shoul we also check for existance of 'preferences' property of user object?

Avatar
Brian Lonsdorf

You totally can! We can check everything we feel like.

In reply to Egghead
Avatar
Egghead

Hi Brian,
Thanks for reponse, one question regarding 'checking' if something exist or if parameters are 'right' type or not empty, what is your approach or best practice, do you check everything for existance(or if parameters are right type or not empty)?

In reply to Brian Lonsdorf
Avatar
Brian Lonsdorf

I think the best practice is to return Either's from low level "partial" functions that might return null. If they do that, then when you're at an application level, you've ensured existence at the edges so you don't end up with a bunch of unnecessary (paranoia-driven-development) checks in your main logic.

In reply to Egghead
Avatar
Luis Silva

In parseDbUrl example, there is a small difference between the imperative code and the functional, if the c.url is falsy the imperative will return undefined and the functional will return null.

Avatar
Nik

Hi Alexander, wouldn't
js
preview => Object.assign({ preview }, example)
potentially
just return the original example should it already had a preview value because .assign() basically says take values from right hand side object(s) and insert it into the one(s) on the left.?

In reply to Alexander
Avatar
Yannick

@Nik,
Hello Nik,
I think you're right.
If example has a preview property on it, it will override the important change statement that is the preview property freshly created.
I think the common use case is to put at the right side properties that we want to update in the object that is on the left, but not the contrary.
But if we do like so : Object.assign(example, {preview}), then we mutate example...
I think that's why Alexander wrote that it would be nice and obvious to use: Object.assign({}, example, {preview})
(But even like this, what if example had properties on its prototype chain? They will disappear ...?)
Because whatever, Brian just wanted to give us some examples to understand functional way of coding.

In reply to Nik

All right, class. It's movie time. Hit the lights, please. We're going to see various examples of imperative code, compared to the equivalent composed expressions using Either. Enjoy.

cue retro game music

Example 1

const openSite = () => {
    if(current_user) {
        return renderPage(current_user)
    } else {
        return showLogin()
    }
}

cosnt openSite = () => 
    fromNullable(current_user)
    .fold(showLogin, renderPage)

Example 2

const getPrefs = user => {
    if(user.premium) {
        return loadPrefs(user.preferences)
    } else {
        return defaultPrefs
    }
}

const getPrefs = user =>
    (user.premium ? Right(user) : Left('not premium'))
    .map(u => u.preferences)
    .fold(() => defaultPrefs, prefs => loadPrefs(prefs))

Example 3

const streetName = user => {
    const address = user.address

    if(address) {
        const street = address.street

        if(street) {
            return street.name
        }
    }
    return 'no street'
}

const streetName = user =>
    fromNullable(user.address)
    .chain(a => frommNullable(a.street))
    .map(s => s.name)
    .fold(e => 'no street', n => n)

Example 4

const concatUniq = (x, ys) => {
    const found = ys.filter(y => y === x)[0]
    return found ? ys : ys.concat(x)
}

const concatUniq = (x, ys) =>
    fromNullable(ys.filter(y => y === x)[0])
    .fold(() => ys.concat(x), y => ys)

Example 5

const wrapExamples = example => {
    if(example.previewPath) {
        try {
            example.preview = fs.readFileSync(example.previewPath)
        } catch(e) { }
    }
    return example
}

const readFile = x => tryCatch(() => fs.readFileSync(x))

const wrapExample = example =>
    fromNullable(example.previewPath)
    .chain(readFile)
    .fold(() => example,
          ex => Object.assign({preview: p}, ex))

Example 6

const parseDbUrl = cfg => {
    try {
        const c = JSON.parse(cfg)
        if(c.url) {
            return c.url.match(/postgres:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/(.+)/)
        }
    } catch(e) {
        return null
    }
}

const parseDbUrl = cfg =>
    tryCatch(() => JSON.parse(cfg))
    .chain(c => fromNullable(c.url))
    .fold(e => null,
          u => u.match(/postgres:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/(.+)/))

GAME OVER

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