4

I'm exploring these two libs and for me ImmutableJS has (mostly) immutable data structures whereas Ramda has swiss army knife set of FP utils.

When I google I see articles like Ramda vs ImmutableJS that recommend one or the other, but at first glance, at least to me, they complement each other.

I can imagine having all my data structures in React app to be ImmutableJS (List, Set, Map, Record) but use Ramda to compose functions, make transformations on ImmutableJS collections etc or when I miss some features like uniq.

What do you think? Is it sensible approach?

dragonfly
  • 17,407
  • 30
  • 110
  • 219
  • 3
    I guess the problem is that Ramda doesn't work with ImmtuableJS types. You either need a compatibility wrapper or you have to stick with the IJS combinators and handle conversions from IJS to JS Object types (that Ramda expects) as a last resort. –  Apr 05 '19 at 14:53

2 Answers2

3

Can they be used together; not smoothly or seamlessly.

It is most probably an approach that, as things stand currently, will lead you toward at least some difficulty, and most probably a great deal of difficulty. The reason for this is that immutable's structures are not compatible with ramda's functions. You may be able to create wrappers or an interop to patch this functionality in, but this seems like a fairly big project.

This issue goes into further detail, and includes some potential alternatives to immutablejs such as List.

Here's a very small example of why the lack of interoperability is a problem:

const { Map } = Immutable;
const { path } = R;

const standardObject = {a: 1, b: 2, c: 3};
const map1 = Immutable.Map(standardObject);

const getA = path(['a']);

const result = getA(map1);
const defaultResult = getA(standardObject);

console.dir(result);
console.dir(defaultResult);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.js"></script>

You could presumably build the conversions into the work you're doing in ramda; this seems like the simplest way around the problem though it does mean you'd be tying your code very closely to immutable data structures. That might work like this:

const { Map } = Immutable;
const { path, pipe } = R;

const standardObject = {a: 1, b: 2, c: 3};
const map1 = Immutable.Map(standardObject);

const toStandard = map => map.toObject()

const getA = pipe(
  toStandard,
  path(['a'])
)

const result = getA(map1)

console.dir(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.js"></script>
OliverRadini
  • 6,238
  • 1
  • 21
  • 46
  • Thanks a lot! List looks great. Do you know any similar libs for i.e. maps/records? – dragonfly Apr 05 '19 at 16:46
  • 1
    It doesn't change the point, but note that the use of `R.path` is wrong here. It should either be `prop('a')` or `path(['a'])`. This only works coincidentally because `'a'` has `length` of 1 and `'a'[0]` is just `'a'`. – Scott Sauyet Apr 05 '19 at 19:15
  • 1
    @ScottSauyet Many thanks for pointing that out! I've updated the answer now – OliverRadini Apr 05 '19 at 22:06
  • @dragonfly I'm afraid I don't know of any other such libraries. `List` seems to be fairly unusual in having ramda compatibility built in. I've edited the answer with some detail on how you might use `Map` etc. with ramda – OliverRadini Apr 05 '19 at 22:19
1

Some of this integration comes free with Ramda. Ramda delegates many of its calls to the data object. Mostly, if the name of a Ramda function is the same as the name of an Immutable method, then Ramda will perform the integration.

This means that you can often use an Immutable List or Map with Ramda where you would usually use an Array or Object.

const {Map, List} = immutable
const {map, filter, find} = ramda

const square = n => n * n
const isEven = n => n % 2 == 0

const xs = new List([1, 2, 3, 4, 5])

console.log(map(square, xs)) //=> List [1, 4, 9, 16, 25]
console.log(filter(isEven, xs)) //=> List [2, 4]
console.log(find(n => n > 3, xs)) //=> 3

const x = new Map({a: 1, b: 2, c: 3, d: 4, e: 5});

console.log(map(square, x))
//=> Map {"a" => 1, "b" => 4, "c" => 9, "d" => 16, "e" => 25}
console.log(filter(isEven, x)) //=> Map {"c" => 3, "d" => 4, "e" => 5}
<script src="https://bundle.run/ramda@0.26.1"></script>
<script src="https://bundle.run/immutable@4.0.0-rc.12"></script>

This is limited, though, for now by the shared names. And not all of Ramda's functions delegate this way.

As the issue mentioned by Oliver Radini describes, I have some real interest in making it easier in Ramda to do further integrations with tools like Immutable, but it's never made it to the top of the list, and there is some real pushback among the Ramda contributors.

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103