This article targets an audience that’s graduating from functional libraries like `ramda` to using Algebraic Data Types. We’re using the excellent `crocks` library for our ADTs and helpers, although these concepts may apply to other ones as well. We’ll be focusing on demonstrating practical applications and patterns without delving into a lot of theory.

#### Safely Executing Dangerous Functions

Let’s say we have a situation where we want to use a function called `darken` from a third-party library. `darken` takes a multiplier, a color and returns a darker shade of that color.

``````// darken :: Number -> String -> String
darken(0.1)("gray")
//=> "#343434"``````

Pretty handy for our CSS needs. But it turns out that the function is not as innocent as it seems. `darken` throws errors when it receives unexpected arguments!

``````darken(0.1)(null)
=> // Error: Passed an incorrect argument to a color function, please pass a string representation of a color.
``````

This is, of course, very helpful for debugging — but we wouldn’t want our application to blow up just because we couldn’t derive a color. Here’s where `tryCatch` comes to the rescue.

``````import { darken } from "polished"
import { tryCatch, compose, either, constant, identity, curry } from "crocks"

// safeDarken :: Number -> String -> String
const safeDarken = curry(n =>
compose(
either(constant("inherit"), identity),
tryCatch(darken(n))
)
)``````

`tryCatch` executes the provided function within a try-catch block and returns a Sum Type called `Result`. In its essence, a Sum Type is basically an “or” type. This means that the `Result` could be either an `Ok` if an operation is successful or an `Error` in case of failures. Other examples of Sum Types include `Maybe`, `Either`, `Async` and so on. The `either` point-free helper breaks the value out of the `Result` box, and returns the CSS default `inherit` if things went south or the darkened color if everything went well.

``````safeDarken(0.5)(null)
//=> inherit

safeDarken(0.25)('green')
//=> '#004d00'``````

#### Enforcing Types using Maybe Helpers

With JavaScript, we often run into cases where our functions explode because we’re expecting a particular data type, but we receive a different one instead. `crocks` provides the `safe`, `safeAfter` and `safeLift` functions that allow us to execute code more predictably by using the `Maybe` type. Let’s look at a way to convert camelCased strings into Title Case.

``````import { safeAfter, safeLift, isArray, isString, map, compose, option } from "crocks"

// match :: Regex -> String -> Maybe [String]
const match = regex => safeAfter(isArray, str => str.match(regex))

// join :: String -> [String] -> String
const join = separator => array => array.join(separator)

// upperFirst :: String -> String
const upperFirst = x =>
x.charAt(0)
.toUpperCase()
.concat(x.slice(1).toLowerCase())

// uncamelize :: String -> Maybe String
const uncamelize = safeLift(isString, compose(
option(""),
map(compose(join(" "), map(upperFirst))),
match(/(((^[a-z]|[A-Z])[a-z]*)|[0-9]+)/g),
))

uncamelize("rockTheCamel")
//=> Just "Rock The Camel"

uncamelize({})
//=> Nothing``````

We’ve created a helper function `match` that uses `safeAfter` to iron out `String.prototype.match`’s behavior of returning an `undefined` in case there are no matches. The `isArray` predicate ensures that we receive a `Nothing` if there are no matches found, and a `Just [String]` in case of matches. `safeAfter` is great for executing existing or third-party functions in a reliable safe manner.

(Tip: `safeAfter` works really well with `ramda` functions that return `a | undefined`.)

Our `uncamelize 🐪` function is executed with `safeLift(isString)` which means that it’ll only execute when the input returns true for the `isString`predicate.

In addition to this, crocks also provides the `prop` and `propPath` helpers which allow you to pick properties from `Object`s and `Array`s.

``````import { prop, propPath, map, compose } from "crocks"

const goodObject = {
name: "Bob",
bankBalance: 7999,
city: "Auckland",
country: "New Zealand",
},
}

prop("name")(goodObject)
//=> Just "Bob"
//=> Just "Auckland"

// getBankBalance :: Object -> Maybe String
const getBankBalance = compose(
map(balance => balance.toFixed(2)),
prop("bankBalance")
)

getBankBalance(goodObject)
//=> Just '7999.00'
getBankBalance({})
//=> Nothing``````

This is great, especially if we’re dealing with data from side-effects that are not under our control like API responses. But what happens if the API developers suddenly decide to handle formatting at their end?

``````const badObject = {
name: "Rambo",
bankBalance: "100.00",
city: "Hope",
country: "USA"
}
}

getBankBalance(badObject) // TypeError: balance.toFixed is not a function :-(``````

Runtime errors! We tried to invoke the `toFixed` method on a String, which doesn’t really exist. We need to make sure that `bankBalance` is really a `Number` before we invoke `toFixed` on it. Let’s try to solve it with our `safe` helper.

``````import { prop, propPath, compose, map, chain, safe, isNumber } from "crocks"

// getBankBalance :: Object -> Maybe String
const getBankBalance = compose(
map(balance => balance.toFixed(2)),
chain(safe(isNumber)),
prop("bankBalance")
)

getBankBalance(goodObject) //=> Just '7999.00'``````

We pipe the results of the `prop` function to our `safe(isNumber)` function which also returns a `Maybe`, depending on whether the result of `prop`satisfies the predicate. The pipeline above guarantees that the last `map`which contains the `toFixed` will only be called when `bankBalance` is a `Number`.

If you’re going to be dealing with a lot of similar cases, it would make sense to extract this pattern as a helper:

``````import { Maybe, ifElse, prop, chain, curry, compose, isNumber } from "crocks"

const { of, zero } = Maybe

// propIf :: (a -> Boolean) -> [String | Number] -> Maybe a
const propIf = curry((fn, path) =>
compose(
chain(ifElse(fn, of, zero)),
prop(path)
)
)

propIf(isNumber, "age", goodObject)
//=> Just 7999
//=> Nothing``````

#### Using Applicatives to keep Functions Clean

Often times, we find ourselves in situations where we would want to use an existing function with values wrapped in a container. Let’s try to design a safe `add` function that allows only numbers, using the concepts from the previous section. Here’s our first attempt.

``````import { Maybe, safe, isNumber } from "crocks"

// safeNumber :: a -> Maybe a
const safeNumber = safe(isNumber)

// add :: a -> b -> Maybe Number
const add = (a, b) => {
const maybeA = safeNumber(a)
const maybeB = safeNumber(b)

return maybeA.chain(
valA => maybeB.map(valB => valA + valB)
)
}

//=> Just 3

//=> Nothing``````

This does exactly what we need, but our `add` function is no longer a simple `a + b`. It has to first lift our values into `Maybe`s, then reach into them to access the values, and then return the result. We need to find a way to preserve the core functionality of our `add` function while allowing it to work with values contained in ADTs! Here’s where Applicative Functors come in handy.

An Applicative Functor is just a like a regular functor, but along with `map`, it also implements two additional methods:

``of :: Applicative f => a -> f a``

The `of` is a completely dumb constructor, and lifts any value that you give it into our data type. It’s also referred to as `pure` in other languages.

``````Maybe.of(null)
//=> Just null

Const.of(42)
//=> Const 42``````

And here’s where all the money is — the `ap` method:

``ap :: Apply f => f a ~> f (a -> b) -> f b``

The signature looks very similar to `map`, with the only difference being that our `a -> b` function is also wrapped in an `f`. Let’s see this in action.

``````import { Maybe, safe, isNumber } from "crocks"

// safeNumber :: a -> Maybe a
const safeNumber = safe(isNumber)

// add :: a -> b -> c
const add = a => b => a + b

// add :: a -> b -> Maybe Number
.ap(safeNumber(a))
.ap(safeNumber(b))

//=> Just 3

//=> Nothing``````

We first lift our curried `add` function into a `Maybe`, and then apply `Maybe a`and `Maybe b` to it. We’ve been using `map` so far to access the value inside a container and `ap` is no different. Internally, it `map`s on `safeNumber(a)` to access the `a` and applies it to `add`. This results in a `Maybe` that contains a partially applied `add`. We repeat the same process with `safeNumber(b)` to execute our `add` function, resulting in a `Just` of the result if both `a` and `b`are valid or a `Nothing` otherwise.

Crocks also provides us the `liftA2` and `liftN` helpers to express the same concept in a pointfree manner. A trivial example follows:

``````liftA2(add)(Maybe(1))(Maybe(2))
//=> Just 3``````

We shall use this helper extensively in the section `Expressing Parallelism`.

Tip: Since we’ve observed that `ap` uses `map` to access values, we can do cool things like generating a Cartesian product when given two lists.

``````import { List, Maybe, Pair, liftA2 } from "crocks"

const names = List(["Henry", "George", "Bono"])
const hobbies = List(["Music", "Football"])

List(name => hobby => Pair(name, hobby))
.ap(names)
.ap(hobbies)
// => List [ Pair( "Henry", "Music" ), Pair( "Henry", "Football" ),
// Pair( "George", "Music" ), Pair( "George", "Football" ),
// Pair( "Bono", "Music" ), Pair( "Bono", "Football" ) ]``````

#### Using Async for Predictable Error Handling

`crocks` provides the `Async` data type that allows us to build lazy asynchronous computations. To know more about it, you can refer to the extensive official documentation here. This section aims to provide examples of how we can use `Async` to improve the quality of our error reporting and make our code resilient.

Often, we run into cases where we want to make API calls that depend on each other. Here, the `getUser` endpoint returns a user entity from GitHub and the response contains a lot of embedded URLs for repositories, stars, favorites and so on. We will see how we can design this use case with using `Async`.

``````import { Async, prop, compose, chain,  safe, isString, maybeToAsync } from "crocks"

const { fromPromise } = Async

// userPromise :: String -> Promise User Error
const userPromise = user => fetch(`https://api.github.com/users/\${user}`)
.then(res => res.json())

// resourcePromise :: String -> Promise Resource Error
const resourcePromise = url => fetch(url)
.then(res => res.json())

// getUser :: String -> Async User Error
const getUser = compose(
chain(fromPromise(userPromise)),
maybeToAsync('getUser expects a string'),
safe(isString)
)

// getResource :: String -> Object -> Async Resource Error
const getResource = path => user => {
if (!isString(path)) {
return Async.Rejected("getResource expects a string")
}
return maybeToAsync("Error: Malformed user response received", prop(path, user))
.chain(fromPromise(resourcePromise))
}

// logError :: (...a) -> IO()
const logError = (...args) => console.log("Error: ", ...args)

// logResponse :: (...a) -> IO()
const logSuccess = (...args) => console.log("Success: ", ...args)

getUser("octocat")
.chain(getResource("repos_url"))
.fork(logError, logSuccess)
//=> Success: { ...response }

getUser(null)
.chain(getResource("repos_url"))
.fork(logError, logSuccess)
//=> Error: The user must be as string

getUser("octocat")
.chain(getResource(null))
.fork(logError, logSuccess)
//=> Error: getResource expects a string

getUser("octocat")
.chain(getResource("unknown_path_here"))
.fork(logError, logSuccess)
//=> Error: Malformed user response received``````

The usage of the `maybeToAsync` transformation allows us to use all of the safety features that we get from using `Maybe` and bring them to our `Async`flows. We can now flag input and other errors as a part of our `Async` flows.

#### Using Monoids Effectively

We’ve already been using Monoids when we perform operations like `String`/`Array` concatenation and number addition in native JavaScript. It’s simply a data type that offers us the following methods.

``concat :: Monoid m => m a -> m a -> m a``

`concat` allows us to combine two Monoids of the same type together with a pre-specified operation.

``empty :: Monoid m => () => m a``

The `empty` method provides us with an identity element, that when `concat` ed with other Monoids of the same type, would return the same element. Here’s what I’m talking about.

``````import { Sum } from "crocks"

Sum.empty()
//=> Sum 0

Sum(10)
.concat(Sum.empty())
//=> Sum 10

Sum(10)
.concat(Sum(32))
//=> Sum 42``````

By itself, this doesn’t look very useful, but `crocks` provides some additional Monoids along with helpers `mconcat`, `mreduce`, `mconcatMap` and `mreduceMap`.

``````import { Sum, mconcat, mreduce, mconcatMap, mreduceMap } from "crocks"

const array = [1, 3, 5, 7, 9]

const inc = x => x + 1

mconcat(Sum, array)
//=> Sum 25

mreduce(Sum, array)
//=> 25

mconcatMap(Sum, inc, array)
//=> Sum 30

mreduceMap(Sum, inc, array)
//=> 30``````

The `mconcat` and `mreduce` methods take a Monoid and a list of elements to work with, and apply `concat` to all of their elements. The only difference between them is that `mconcat` returns an instance of the Monoid while `mreduce` returns the raw value. The `mconcatMap` and `mreduceMap` helpers work in the same way, except that they accept an additional function that is used to map over every element before calling `concat`.

Let’s look at another example of a Monoid from `crocks`, the `First` Monoid. When concatenating, `First` will always return the first, non-empty value.

``````import { First, Maybe } from "crocks"

First(Maybe.zero())
.concat(First(Maybe.zero()))
.concat(First(Maybe.of(5)))
//=> First (Just 5)

First(Maybe.of(5))
.concat(First(Maybe.zero()))
.concat(First(Maybe.of(10)))
//=> First (Just 5)``````

Using the power of `First`, let’s try creating a function that attempts to get the first available property on an object.

``````import { curry, First, mreduceMap, flip, prop, compose } from "crocks"

/** tryProps -> a -> [String] -> Object -> b */
const tryProps = flip(object =>
mreduceMap(
First,
flip(prop, object),
)
)

const a = {
x: 5,
z: 10,
m: 15,
g: 12
}

tryProps(["a", "y", "b", "g"], a)
//=> Just 12

tryProps(["a", "b", "c"], a)
//=> Nothing

tryProps(["a", "z", "c"], a)
//=> Just 10``````

Pretty neat! Here’s another example that tries to create a best-effort formatter when provided different types of values.

``````
import {
applyTo, mreduceMap, isString, isEmpty, mreduce, First, not, isNumber, chain
compose, safe, and, constant, Maybe, map, equals, ifElse, isBoolean, option,
} from "crocks";

// isDate :: a -> Boolean
const isDate = x => x instanceof Date;

// lte :: Number -> Number -> Boolean
const lte = x => y => y <= x;

// formatBoolean :: a -> Maybe String
const formatBoolean = compose(
map(ifElse(equals(true), constant("Yes"), constant("No"))),
safe(isBoolean)
);

// formatNumber :: a -> Maybe String
const formatNumber = compose(
map(n => n.toFixed(2)),
safe(isNumber)
);

// formatPercentage :: a -> Maybe String
const formatPercentage = compose(
map(n => n + "%"),
safe(and(isNumber, lte(100)))
);

// formatDate :: a -> Maybe String
const formatDate = compose(
map(d => d.toISOString().slice(0, 10)),
safe(isDate)
);

// formatString :: a -> Maybe String
const formatString = safe(isString)

// autoFormat :: a -> Maybe String
const autoFormat = value =>
mreduceMap(First, applyTo(value), [
formatBoolean,
formatPercentage,
formatNumber,
formatDate,
formatString
]);

autoFormat(true)
//=> Just "Yes"

autoFormat(10.02)
//=> Just "10%"

autoFormat(255)
//=> Just "255.00"

autoFormat(new Date())
//=> Just "2019-01-14"

autoFormat("YOLO!")
//=> Just "YOLO!"

autoFormat(null)
//=> Nothing``````

#### Expressing Parallelism in a Pointfree manner

We might run into cases where want to perform multiple operations on a single piece of data and combine the results in some way. `crocks` provides us with two methods to achieve this. The first pattern leverages Product Types `Pair` and `Tuple`. Let’s look at a small example where we have an object that looks like this:

``{ ids: [11233, 12351, 16312], rejections:  }``

We would like to write a function that accepts this object and returns an `Array` of `ids` excluding the rejected ones. Our first attempt in native JavaScript would look like this:

``const getIds = (object) => object.ids.filter(x => object.rejections.includes(x))``

This of course works, but it would explode in case one of the properties is malformed or is not defined. Let’s make `getIds` return a `Maybe` instead. We use `fanout` helper that accepts two functions, runs it on the same input and returns a `Pair` of the results.

``````import { prop, compose, equals, filter, fanout, merge, liftA2 } from "crocks"

/**
* object :: Record
* Record :: {
*  ids: [Number]
*  rejection: [Number]
* }
**/
const object = { ids: [11233, 12351, 16312], rejections:  }

// excludes :: [a] -> [b] -> Boolean
const excludes = x => y => !x.includes(y)

// difference :: [a] -> [a] -> [a]
const difference = compose(filter, excludes)

// getIds :: Record -> Maybe [Number]
const getIds = compose(
merge(liftA2(difference)),
fanout(prop("rejections"), prop("ids"))
)

getIds(object)
//=> Just [ 12351, 16312 ]

getIds({ something: [], else: 5 })
//=> Nothing``````

One of the main benefits of using the pointfree approach is that it encourages us to break our logic into smaller pieces. We now have the reusable helper `difference` (with `liftA2`, as seen previously) that we can use to `merge` both halves the `Pair` together.

The second method would be to use the `converge` combinator to achieve similar results. `converge` takes three functions and an input value. It then applies the input to the second and third function and pipes the results of both into the first. Let’s use it to create a function that normalizes an `Array`of objects based on their `id`s. We will use the `Assign` Monoid that allows us to combine objects together.

``````import {
mreduceMap, applyTo, option, identity, objOf, map,
converge, compose, Assign, isString, constant
} from "crocks"
import propIf from "./propIf"

// normalize :: String -> [Object] -> Object
const normalize = mreduceMap(
Assign,
converge(
applyTo,
identity,
compose(
option(constant({})),
map(objOf),
propIf(isString, "id")
)
)
)

normalize([{ id: "1", name: "Kerninghan" }, { id: "2", name: "Stallman" }])
//=> { 1: { id: '1', name: 'Kerninghan' }, 2: { id: '2', name: 'Stallman' } }

normalize([{ id: null}, { id: "1", name: "Knuth" }, { totally: "unexpected" }])
//=> { 1: { id: '1', name: 'Knuth' } }``````

#### Using Traverse and Sequence to Ensure Data Sanity

We’ve seen how to use `Maybe` and friends to ensure that we’re always working with the types we expect. But what happens when we’re working with a type that contains other values, like an `Array` or a `List` for example? Let’s look at a simple function that gives us the total length of all strings contained within an `Array`.

``````import { compose, safe, isArray, reduce, map } from "crocks"

// sum :: [Number] -> Number
const sum = reduce((a, b) => a + b, 0)

// length :: [a] -> Number
const length = x => x.length;

// totalLength :: [String] -> Maybe Number
const totalLength = compose(
map(sum),
map(map(length)),
safe(isArray)
)

const goodInput = ["is", "this", "the", "real", "life?"]
totalLength(goodInput)
//=> Just 18

const badInput = { message: "muhuhahhahahaha!"}
//=> Nothing``````

Great. We’ve made sure our function always returns a `Nothing` if it doesn’t receive an `Array`. Is this enough, though?

``````totalLength(["stairway", "to", undefined])
//=> TypeError: x is undefined``````

Not really. Our function doesn’t guarantee that the contents of the list won’t hold any surprises. One of the ways we could solve this would be to define a `safeLength` function that only works with strings:

``````// safeLength :: a -> Maybe Number
const safeLength = safeLift(isString, length)``````

If we use `safeLength` instead of `length` as our mapping function, we would receive a `[Maybe Number]` instead of a `[Number]` and we cannot use our `sum`function anymore. Here’s where `sequence` comes in handy.

``````import { sequence, Maybe, Identity } from "crocks"

sequence(Maybe, Identity(Maybe.of(1)))
//=> Just Identity 1

sequence(Array, Identity([1,2,3]))
//=> [ Identity 1, Identity 2, Identity 3 ]

sequence(Maybe, [Maybe.of(4), Maybe.of(2)])
//=> Just [ 4, 2 ]

sequence(Maybe, [Maybe.of(4), Maybe.zero()])
//=> Nothing``````

`sequence` helps swap the inner type with the outer type while performing a certain `effect`, given that the inner type is an Applicative. The `sequence `on `Identity` is pretty dumb — it just `map`s over the inner type and returns the contents wrapped in an `Identity` container. For `List` and `Array`, `sequence`uses `reduce` on the list to combine its contents using `ap` and `concat`. Let’s see this in action in our refactored `totalLength` implementation.

``````// totalLength :: [String] -> Maybe Number
const totalLength = compose(
map(sum),
chain(sequence(Maybe)),
map(map(safeLength)),
safe(isArray)
)

const goodString = ["is", "this", "the", "real", "life?"]
totalLength(goodString)
//=> Just 18

totalLength(["stairway", "to", undefined])
//=> Nothing``````

Great! We’ve built a completely bulletproof `totalLength`. This pattern of mapping over something from `a -> m b` and then using `sequence` is so common that we have another helper called `traverse` which performs both operations together. Let’s see how we can use `traverse` instead of sequence in the above example.

``````// totalLengthT :: [String] -> Maybe Number
const totalLengthT = compose(
map(sum),
chain(traverse(Maybe, safeLength)),
safe(isArray)
)``````

There! It works exactly the same way. If we think about it, our `sequence`operator is basically `traverse`, with an `identity` as the mapping function.

Note: Since we cannot infer inner type using JavaScript, we have to explicitly provide the type constructor as the first argument to `traverse` and `sequence`.

It’s easy to see how `sequence` and `traverse` are invaluable for validating data. Let’s try to create a generic validator that takes a schema and validates an input object. We’ll use the `Result` type, which accepts a Semigroup on the left side that allows us to collect errors. A Semigroup is similar to a Monoid and it defines a `concat` method — but unlike the Monoid, it doesn’t require the presence of the `empty` method. We’re also introducing the transformation function `maybeToResult` below, that’ll help us interoperate between `Maybe` and `Result`.

``````
import {
Result, isString, map, merge, constant, bimap, flip, propOr, identity,
toPairs, safe, maybeToResult, traverse, and, isNumber, compose
} from "crocks"

// length :: [a] -> Int
const length = x => x.length

// gte :: Number -> a -> Result String a
const gte = x => y => y >= x

// lte :: Number -> a -> Result String a
const lte = x => y => y <= x

// isValidName :: a -> Result String a
const isValidName = compose(
maybeToResult("expected a string less than 20 characters"),
safe(and(compose(lte(20), length), isString))
)

// isAdult :: a -> Result String a
maybeToResult("expected a value greater than 18"),
safe(and(isNumber, gte(18)))
)

/**
*  schema :: Schema
*  Schema :: {
*    [string]: a -> Result String a
*  }
* */
const schema = {
name: isValidName,
}

// makeValidator :: Schema -> Object -> Result [String] Object
const makeValidator = flip(object =>
compose(
map(constant(object)),
traverse(Result, merge((key, validator) =>
compose(
bimap(error => [`\${key}: \${error}`], identity),
validator,
propOr(undefined, key)
)(object)
)
),
toPairs
)
)

// validate :: Object -> Result [String] Object
const validate = makeValidator(schema)

validate(({
name: "Car",
age: 21,
}))
//=> Ok { name: "Car", age: 21 }

validate(({
name: 7,
age: "Old",
}))
//=>  Err [ "name: expected a string less than 20 characters", "age: expected a value greater than 18" ]``````

Since we’ve flipped the `makeValidator` function to make more suitable for currying, our `compose` chain receives the schema that we need to validate against first. We first break the schema into key-value `Pair`s, and pass the value of each property to it’s corresponding validation function. In case the function fails, we use `bimap` to map on the error, add some more information to it, and return it as a singleton `Array`. `traverse` will then `concat` all the errors if they exist, or return the original object if it’s valid. We could have also returned a `String` instead of an `Array`, but an `Array`feels much nicer.

Thanks to Ian Hofmann-Hicks, Sinisa Louc and Dale Francis for their inputs on this post.