总结

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

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

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

第 10 章: Applicative Functor

练习

  1. // 练习 1
  2. // ==========
  3. // 给定一个 user,使用 safeProp 和 map/join 或 chain 安全地获取 sreet 的 name
  4. var safeProp = _.curry(function (x, o) { return Maybe.of(o[x]); });
  5. var user = {
  6. id: 2,
  7. name: "albert",
  8. address: {
  9. street: {
  10. number: 22,
  11. name: 'Walnut St'
  12. }
  13. }
  14. };
  15. var ex1 = undefined;
  16. // 练习 2
  17. // ==========
  18. // 使用 getFile 获取文件名并删除目录,所以返回值仅仅是文件,然后以纯的方式打印文件
  19. var getFile = function() {
  20. return new IO(function(){ return __filename; });
  21. }
  22. var pureLog = function(x) {
  23. return new IO(function(){
  24. console.log(x);
  25. return 'logged ' + x;
  26. });
  27. }
  28. var ex2 = undefined;
  29. // 练习 3
  30. // ==========
  31. // 使用 getPost() 然后以 post 的 id 调用 getComments()
  32. var getPost = function(i) {
  33. return new Task(function (rej, res) {
  34. setTimeout(function () {
  35. res({ id: i, title: 'Love them tasks' });
  36. }, 300);
  37. });
  38. }
  39. var getComments = function(i) {
  40. return new Task(function (rej, res) {
  41. setTimeout(function () {
  42. res([
  43. {post_id: i, body: "This book should be illegal"},
  44. {post_id: i, body: "Monads are like smelly shallots"}
  45. ]);
  46. }, 300);
  47. });
  48. }
  49. var ex3 = undefined;
  50. // 练习 4
  51. // ==========
  52. // 用 validateEmail、addToMailingList 和 emailBlast 实现 ex4 的类型签名
  53. // addToMailingList :: Email -> IO([Email])
  54. var addToMailingList = (function(list){
  55. return function(email) {
  56. return new IO(function(){
  57. list.push(email);
  58. return list;
  59. });
  60. }
  61. })([]);
  62. function emailBlast(list) {
  63. return new IO(function(){
  64. return 'emailed: ' + list.join(',');
  65. });
  66. }
  67. var validateEmail = function(x){
  68. return x.match(/\S+@\S+\.\S+/) ? (new Right(x)) : (new Left('invalid email'));
  69. }
  70. // ex4 :: Email -> Either String (IO String)
  71. var ex4 = undefined;