Drew Tipson
2 min readFeb 6, 2017

--

With the caveat that I only understand the lodash: afaik, _.chain(x).thru(fn) is basically like _.map over what’s basically an Identity type, which means that this is all just Functors at play, which means this is all just functional composition (which is THE core pattern of functional programming).

You don’t really even need lodash for this, you can just exploit the fact that Arrays are Functors, and treat them as a cheap-o Identity Type by sticking some object into the “box” then taking it back out again at the end (all credit to Brian Lonsdorf here for the intuition/teaching insight)

[yourObject]
.map(function1)
.map(function2)
.map(function3)[0]

But given that it’s functional composition here, that means it’s also just equivalent to doing this…

yourObject => function3(function2(function1(yourObject)))//orcompose(function3, function2, function1)

Of course, it looks like the implication is that those chained functions have side-effects in addition to just transforming data, in which case a functional type that represents the particulars of that operation might make a better container.

//pure description of the operation
completeOperation = Task.of(yourObject)
.map(function1)
.map(function2)
//...
.chain(data=>Task.post('/smsRoute',{data}));
//actually running the side-effecting operation
completeOperation.fork(handleError, reactToResponse)

.tap(fn) is just .map(x=>{ fn(x); return x}), though again if it’s causing side-effects like console.log, purists would probably object (though obviously IO is a bit overkill-for-no-extra-safety in javascript). :)

Of the other related/relevant patterns/Types I know that may be implicated here:

“working on a large object but at each step working on just a small piece of it, immutably” sounds like a heck of a lot like cursors/zippers or, perhaps even more so: composable functional lenses, which can target/focus changes in on just one part of an object but then return the entire transformed object back:

over(
compose(L.user,L.name),
name=>name.toUpperCase(),
someBigObjectIncludingAUser
)
//orusernameLens = compose(L.user, L.name)
upperCaseUsername = over( usernameLens, name=>name.toUpperCase())
[someBigObjectIncludingAUser].map(upperCaseUsername)[0]//orupperCaseUsername(someBigObjectIncludingAUser)

On the other hand, “building up some stateful object” (i.e. having a starting state and then deriving a new state from it via a bunch of chained operations) sounds a heck of a lot like what the State Monad is good for.

--

--

Drew Tipson

Primarily Javascript, potentially personal, possibly pointless. I welcome and am fascinated by your many marvelous opinions.