Mastodon hachyterm.io

Today I watched the course Hardcore Functional Programming in JavaScript, v2.
The instructor, Brian Lonsdorf, shows you functional programming principles with JavaScript and introduces concepts like currying, functors and monads.

One interesting application is the refactoring of a try-catch-block to the Either monad.

const fs = require('fs')

const getPort = () => {
  try {
    const str = fs.readFileSync('config.json')
    const config = JSON.parse(str)
    return config.port
  } catch (e) {
    return 3000
  }
}

const result = getPort()
const Right = (x) => ({
  map: (f) => Right(f(x)),
  chain: (f) => f(x),
  fold: (f, g) => g(x),
  inspect: () => `Right(${x})`,
})

const Left = (x) => ({
  map: (f) => Left(x),
  chain: (f) => Left(x),
  fold: (f, g) => f(x),
  inspect: () => `Left(${x})`,
})

const fromNullable = (x) => (x != null ? Right(x) : Left(null))

/* define this once and then you can use
try/catch everywhere */
const tryCatch = (f) => {
  try {
    return Right(f())
  } catch (e) {
    return Left(e)
  }
}

const readFileSync = (path) => tryCatch(() => fs.readFileSync(path))

const parseJson = (contents) => tryCatch(() => JSON.parse(contents))

const getPort = () => {
  readFileSync('config.json')
    .chain((contents) => parseJson(contents))
    .map((config) => config.port)
    .fold(
      () => 8080,
      (x) => x
    )
}

Now, when you call getPort and there is a configuration file with a port, the function will getThe port, otherwise 8080.

Further Reading