这里具体的操作仅仅加入了chain(maybeToTask)和chain(eigherToTack)。都是同样的效果。在join时很自然的将Task的 functor 转换到另一个Task的 functor。就像窗边的尖刺驱鸟器,从源头扼杀了嵌套。就像他们巴黎(city of the light)人说的:“Mieux vaut prévenir que guérir” - 花一英镑去治疗不如花一盎司用于预防。
总结
Natural Transformations 是操作 functor 的方法。在范畴学中是非常重要的概念,特别是采用多种抽象化机制时,就会用的更多。上述例子,仅仅局限于几个具体的应用中。如上文所言,只要转换类型时,确保可组合性,即可以实现所需要的不同作用 effects。同时可以解决嵌套问题,虽然会将类型同化到最低的共同母类(lowest common denominator),在实际应用中,一般是作用最易变的函子(通常是Task )(functor with most volatile effects)。
// nt :: (Functor f, Functor g) => f a -> g a
compose(map(f), nt) === compose(nt, map(f));
// idToMaybe :: Identity a -> Maybe a
const idToMaybe = x => Maybe.of(x.$value);
// idToIO :: Identity a -> IO a
const idToIO = x => IO.of(x.$value);
// eitherToTask :: Either a b -> Task a b
const eitherToTask = either(Task.rejected, Task.of);
// ioToTask :: IO a -> Task () a
const ioToTask = x => new Task((reject, resolve) => resolve(x.unsafePerform()));
// maybeToTask :: Maybe a -> Task () a
const maybeToTask = x => (x.isNothing ? Task.rejected() : Task.of(x.$value));
// arrayToMaybe :: [a] -> Maybe a
const arrayToMaybe = x => Maybe.of(x[0]);
// arrayToList :: [a] -> List a
const arrayToList = List.of;
const doListyThings = compose(sortBy(h), filter(g), arrayToList, map(f));
const doListyThings_ = compose(sortBy(h), filter(g), map(f), arrayToList); // law applied
// promiseToTask :: Promise a b -> Task a b
const promiseToTask = x => new Task((reject, resolve) => x.then(resolve).catch(reject));
// taskToPromise :: Task a b -> Promise a b
const taskToPromise = x => new Promise((resolve, reject) => x.fork(reject, resolve));
const x = Promise.resolve('ring');
taskToPromise(promiseToTask(x)) === x;
const y = Task.of('rabbit');
promiseToTask(taskToPromise(y)) === y;