// > foldM :: (Monad a) => (a -> b -> m a) -> a -> [b] -> m a
const foldM = (monad) => (f, a, list) =>
list.length === 0
? monad.pure(a)
: monad.bind(
f(a, list[0]),
fax => foldM(monad)(f, fax, list.slice(1))
)
// > foldP :: (a -> b -> p a) -> a -> [b] -> p a
const foldP = foldM({
pure: x => Promise.resolve(x),
fmap: (f, g) => g.then(f),
bind: (f, g) => f.then(g)
})
// > waterfall :: x -> [x -> Promise x] -> Promise x
const waterfall = (x, fs) =>
foldP((a, y) => y (a), x, fs)
const square = x => Promise.resolve(x * x)
waterfall(2, [square, square, square, square])
.then(console.log)