The reader monad in JavaScript

October 06, 2016

Imagine we have some functions that take the same argument:

function getUser(userId) {
  return function(db) {
    return db.users[userId];
  };
}

function setUser(userId, user) {
  return function(db) {
    db.users[userId] = user;
  };
}

Write a function reader that lets us compose them into db-dependent functions:

function getUserName(userId) {
  return reader(getUser(userId)).map(function(user) {
    return user.name;
  });
}

function setUserName(userId, newName) {
  return reader(getUser(userId)).bind(function(user) {
    user.name = newName;
    return reader(setUser(userId, user));
  });
}

function changeUserName(userId, newName) {
  return getUserName(userId).bind(function(oldName) {
    return setUserName(userId, newName).map(function() {
      return [ 'User'
             , userId
             , ': name changed from'
             , oldName
             , 'to'
             , newName
             ].join(' ');
    });
  });
}

This lets us invoke changeUserName by injecting a db:

var db = {
  users: {
    42: {
      name: 'John Doe',
    },
  },
};

var result = changeUserName(42, 'Jack Doe').run(db);

console.log(result); // User 42 : name changed from John Doe to Jack Doe