总结&练习

monad 让我们深入到嵌套的运算当中,使我们能够在完全避免回调金字塔(pyramid of doom)情况下,为变量赋值,运行有序的作用,执行异步任务等等。当一个值被困在几层相同类型的容器中时,monad 能够拯救它。借助 “pointed” 这个可靠的帮手,monad 能够借给我们从盒子中取出的值,而且知道我们会在结束使用后还给它。

是的,monad 非常强大,但我们还需要一些额外的容器函数。比如,假设我们想同时运行一个列表里的 API 调用,然后再搜集返回的结果,怎么办?是可以使用 monad 实现这个任务,但必须要等每一个 API 完成后才能调用下一个。合并多个合法性验证呢?我们想要的肯定是持续验证以搜集错误列表,但是 monad 会在第一个 Left 登场的时候停掉整个演出。

下一章,我们将看到 applicative functor 如何融入这个容器世界,以及为何在很多情况下它比 monad 更好用。

// 练习 1
// ==========
// 给定一个 user,使用 safeProp 和 map/join 或 chain 安全地获取 sreet 的 name

var safeProp = _.curry(function (x, o) { return Maybe.of(o[x]); });
var user = {
  id: 2,
  name: "albert",
  address: {
    street: {
      number: 22,
      name: 'Walnut St'
    }
  }
};

var ex1 = undefined;


// 练习 2
// ==========
// 使用 getFile 获取文件名并删除目录,所以返回值仅仅是文件,然后以纯的方式打印文件

var getFile = function() {
  return new IO(function(){ return __filename; });
}

var pureLog = function(x) {
  return new IO(function(){
    console.log(x);
    return 'logged ' + x;
  });
}

var ex2 = undefined;



// 练习 3
// ==========
// 使用 getPost() 然后以 post 的 id 调用 getComments()
var getPost = function(i) {
  return new Task(function (rej, res) {
    setTimeout(function () {
      res({ id: i, title: 'Love them tasks' });
    }, 300);
  });
}

var getComments = function(i) {
  return new Task(function (rej, res) {
    setTimeout(function () {
      res([
        {post_id: i, body: "This book should be illegal"},
        {post_id: i, body: "Monads are like smelly shallots"}
      ]);
    }, 300);
  });
}


var ex3 = undefined;


// 练习 4
// ==========
// 用 validateEmail、addToMailingList 和 emailBlast 实现 ex4 的类型签名

//  addToMailingList :: Email -> IO([Email])
var addToMailingList = (function(list){
  return function(email) {
    return new IO(function(){
      list.push(email);
      return list;
    });
  }
})([]);

function emailBlast(list) {
  return new IO(function(){
    return 'emailed: ' + list.join(',');
  });
}

var validateEmail = function(x){
  return x.match(/\S+@\S+\.\S+/) ? (new Right(x)) : (new Left('invalid email'));
}

//  ex4 :: Email -> Either String (IO String)
var ex4 = undefined;