Open admhemed opened 4 years ago
I also encountered the same problem,example code :
// Task(functor,applicative,monad)
const Task = fork => ({
map: f => Task((reject, resolve) =>
fork(reject, a => resolve(f(a)))),
ap: fn =>
Task((reject, resolve) => fork(reject, a =>
fn.map(a).fork(reject, resolve)
)),
chain: f =>
Task((reject, resolve) => fork(reject, a =>
f(a).fork(reject, resolve))),
fork,
[Symbol.for('nodejs.util.inspect.custom')]: () => 'Task(?)'
})
// lift
Task.of = a => Task((_, resolve) => resolve(a))
// --------------------------async------------
// async get user name
const fetchName = Task((_, resolve) => {
setTimeout(() => {
resolve('Melo')
}, 2000)
});
// async get user age
const fetchAge = Task((_, resolve) => {
setTimeout(() => {
resolve(24)
}, 2000)
});
// pure app
const app = Task
.of(name => age => ({ name, age }))
.ap(fetchName)
.ap(fetchAge)
// effect
app.fork(() => {
console.log('something went wrong')
}, x => {
console.log('x', x) // 4 seconds later log {name:'Melo', age:24}
})
“It should be pointed out that part of ap's appeal is the ability to run things concurrently so defining it via chain is missing out on that optimization. Despite that, it's good to have an immediate working interface while one works out the best possible implementation.”
Quote from mostly-adequate-guide
But, the example code take 4 (fetchName 2 + fetchAge 2) seconds !!
How can I call fetchName
and fetchAge
in parallel with the applicative in Task.
Can someone help me rewrite the ap
method ?
Thanks @admhemed and @Sylvenas for bringing this up. I spend hours trying to figure this out. Implemented HTML pages, with real HTTP calls to mocked up JSON data etc. I thought I was mad. But turns out that it's not possible with the implementation given in this book.
I forgot along the way that it was pointed out somewhere..
“It should be pointed out that part of ap's appeal is the ability to run things concurrently so defining it via chain is missing out on that optimization. Despite that, it's good to have an immediate working interface while one works out the best possible implementation.”
Hi,@admhemed & @dotnetCarpenter ,similar to Promise.all
, but the ap
function only needs to receive one Task
.
// Task(functor,applicative,monad)
const Task = fork => ({
map: f => Task((reject, resolve) =>
fork(reject, a => resolve(f(a)))),
ap: fn => Task((reject, resolve) => {
let func, rejected
const firstState = fork(x => {
rejected = true;
return reject(x)
}, x => func = x)
const senondState = fn.fork(x => {
rejected = true;
return reject(x)
}, x => {
if (rejected) return
return resolve(func(x))
})
return [firstState, senondState]
}),
chain: f =>
Task((reject, resolve) => fork(reject, a =>
f(a).fork(reject, resolve))),
fork,
[Symbol.for('nodejs.util.inspect.custom')]: () => 'Task(?)'
})
// lift
Task.of = a => Task((_, resolve) => resolve(a))
The implementation of Task
is not suitable for the book, but it can be used as an appendix, I think this can help some readers.
Another point, if the 2 http requests start instantly, second one may resolve before the first one, and we know renderPage is curried, so how can the second ap use it with its second argument while the first argument is still not available?