Meiosis Wiki

Table of Contents

Ramda

In the previous section, we looked at Lodash-FP to improve our model and nesting functions. We used curried, data-last functions and point-free style.

Ramda is another fine library for functional programming. From its home page:

Ramda emphasizes a purer functional style. Immutability and side-effect free functions are at the heart of its design philosophy. This can help you get the job done with simple, elegant code.

While Lodash-FP was created after Lodash had been in existence for a while, Ramda was designed from the start to provide curried, data-last functions. Choosing between Ramda and Lodash is much like choosing a code editor, IDE, shell, and so on: the best one is the one that makes you most productive.

And again, keep in mind that this is not a requirement for using Meiosis.

Setting a Property

With Lodash-FP, we used _.set:

editDate: evt => update(_.set("date", evt.target.value))

The equivalent function in Ramda is assoc:

editDate: evt => update(R.assoc("date", evt.target.value))

The above is short for update(model => R.assoc("date", evt.target.value, model)). Since R.assoc is curried and data-last, we were able to write the code in point-free style.

We could go one step further. Notice that our function takes evt and pass evt.target.value to R.assoc("date", evt.target.value) which is data-last, and passes the result to update().

We can describe this as the following steps:

We can achieve this using function composition, R.compose to write our function as follows:

editDate: R.compose(update, R.assoc("date"), R.path(["target", "value"]))

R.compose calls functions right-to-left, passing the result of one function to the next.

Using Lenses

With Lodash-FP, we used _.update to update a value using a function:

increase: value => update(_.update("value", _.add(value))),

Recall that this is the equivalent of

increase: value => update(model => _.set("value", _.add(value, _.get("value", model)), model))

With Ramda, the equivalent of _.update is R.over. Instead of just specifying a property, though, R.over expects a lens. In short, a lens is a way of getting and setting a value on an object. For example, a lens for a nested property can be created with R.lensProp("property"), and for a more deeply nested property, R.lensPath(["nested", "property"]).

Once we've created a lens, we pass it to R.over to update the lens target with a function:

increase: value => update(model => R.over(R.lensProp("value"), R.add(value), model))

Notice that again, model is passed as the last argument to the function. Remember that when we have x => f(x), we can make this more concise with the point-free form, f. So, we can write:

increase: value => update(R.over(R.lensProp("value"), R.add(value)))

The result of R.add() is passed to R.over(), which is then passed to update. We can use function composition:

increase: value => R.compose(update, R.over(R.lensProp("value")), R.add(value))

Now value is passed as the last argument, so we can use the point-free form:

increase: R.compose(update, R.over(R.lensProp("value")), R.add)

These functional programming constructs can be very nice, but perhaps harder to decipher when we're not used to them. It's up to you to decide how "far" to go. The more concise form is arguably more elegant, but less explicit as to what is going on.

Principles / Takeaways

Up Next

In the next section, we'll look at using Patchinko.

Table of Contents


Meiosis is developed by @foxdonut00 / foxdonut and is released under the MIT license.