处理多个 functor 作为参数的情况,是 applicative functor 一个非常好的应用场景。借助 applicative functor,我们能够在 functor 的世界里调用函数。尽管已经可以通过 monad 达到这个目的,但在不需要 monad 的特定功能的时候,我们还是更倾向于使用 applicative functor。
至此我们已经基本介绍完容器的 API 了,我们学会了如何对函数调用 map
、chain
和 ap
。下一章,我们将学习如何更好地处理多个 functor,以及如何以一种原则性的方式拆解它们。
require('./support');
var Task = require('data.task');
var _ = require('ramda');
// 模拟浏览器的 localStorage 对象
var localStorage = {};
// 练习 1
// ==========
// 写一个函数,使用 Maybe 和 ap() 实现让两个可能是 null 的数值相加。
// ex1 :: Number -> Number -> Maybe Number
var ex1 = function(x, y) {
};
// 练习 2
// ==========
// 写一个函数,接收两个 Maybe 为参数,让它们相加。使用 liftA2 代替 ap()。
// ex2 :: Maybe Number -> Maybe Number -> Maybe Number
var ex2 = undefined;
// 练习 3
// ==========
// 运行 getPost(n) 和 getComments(n),两者都运行完毕后执行渲染页面的操作。(参数 n 可以是任意值)。
var makeComments = _.reduce(function(acc, c){ return acc+"<li>"+c+"</li>" }, "");
var render = _.curry(function(p, cs) { return "<div>"+p.title+"</div>"+makeComments(cs); });
// ex3 :: Task Error HTML
var ex3 = undefined;
// 练习 4
// ==========
// 写一个 IO,从缓存中读取 player1 和 player2,然后开始游戏。
localStorage.player1 = "toby";
localStorage.player2 = "sally";
var getCache = function(x) {
return new IO(function() { return localStorage[x]; });
}
var game = _.curry(function(p1, p2) { return p1 + ' vs ' + p2; });
// ex4 :: IO String
var ex4 = undefined;
// 帮助函数
// =====================
function getPost(i) {
return new Task(function (rej, res) {
setTimeout(function () { res({ id: i, title: 'Love them futures' }); }, 300);
});
}
function getComments(i) {
return new Task(function (rej, res) {
setTimeout(function () {
res(["This book should be illegal", "Monads are like space burritos"]);
}, 300);
});
}