Lodash is Awesome

HTML

<script src="https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)"></script>
<pre id="output">

</pre>

JavaScript

function customizer(val, op){
  if(_.isFunction(op)){
    return op.apply(this, [val]);
  }
  if(_.isRegExp(op)){
    return op.test(val);
  }
}

// general-purpose, higher-order functions:

var patch = recipe => _.mergeWith(customizer, _, recipe);
var matches = _.isMatchWith(customizer);
var forAll = _.map;
var removeIf = _.reject;
var toggle = _.negate(_.identity);

Function.prototype.onlyIf = function(condFn) {
  return _.cond([[condFn, this]]);
};
Function.prototype.otherwise = function(defaultFn) {
  var noResult = _.flow([this, _.isUndefined]);
  return _.cond([[noResult, defaultFn], [_.T, this]]);
};

// domain-specific functions:

var addItem = item => patch({
  items: _.concat({title: item})
});
var complete = patch({
  completed: true
});
var completeAll = patch({
  items: forAll(complete)
});
var isCompleted = matches({
  complete: true
});
var clearCompleted = patch({
  items: removeIf(isCompleted)
});
var toggleItem = patch({
  completed: toggle
});
var completeItemIf = condFn => patch({
  items: forAll(complete.onlyIf(condFn).otherwise(_.identity))
});
var changeTitleTo = title => patch({
  title: title
});
var hasTitle = title => matches({
  title: title
});
var renameItem = (newTitle, oldTitle) => patch({
  items: forAll(changeTitleTo(newTitle).onlyIf(hasTitle(oldTitle)).otherwise(_.identity))
});
var removeItem = (title) => patch({
  items: removeIf(hasTitle(oldTitle))
});

// demo:

var program = _.flow([
  addItem('Learn Lodash'),
  addItem('Learn FP'),
  addItem('Write Blog Post'),
  renameItem('Learn Functional Programming', 'Learn FP'),
  completeItemIf(hasTitle(/Learn/))
]);

var output = document.getElementById('output');
output.innerHTML = JSON.stringify(program({items: []}), null, 2);