Open puffnfresh opened 7 years ago
Hey @puffnfresh. I'm having trouble wrapping my head around use cases of it for a few reasons. Do you have any in mind that you can share?
Where I'm getting hung up is it seems fold
for any non-settled promise would need to return undefined
(like your never
example). E.g.:
delay(1000, 'delayed').fold(a => true, b => false) == undefined
That seems to imply that folks would often find themselves wanting to call isSettled
before using .fold
. Or perhaps it makes the type more like fold :: Promise e a ~> (e -> b) -> (a -> b) -> Maybe b
. Do you have any thoughts on other ways it could work?
Creed promises aren't lazy, since one of the original design goals was to be ES-Promise compatible while also implementing Fantasy Land. So, fold
wouldn't so much "run" the promise, as synchronously observe it's state at the instant of call (which may be why you quoted "run" in the first place).
Is that what you have in mind?
Yes, I wasn't thinking right - it should always return undefined. I just want to use this for performing side-effects.
No, a promise has more than two states. It's not Either
. It just allows to bimap
over two of those states.
fold
(like you described it) cannot return a b
, as the e
and a
values will only be available asynchronously. At best, it could return a Promise Void b
.
I still don't see your use case. Why not simply use .then(val => true, err => false)
?
Thanks @puffnfresh. I think @bergus's question about .then
is valid. People tend to use then
for side-effects, but I'm interested to hear why you'd prefer an undefined
-returning fold
over ES then
.
Thinking about it myself, I can imagine a few potentially interesting things about fold
(I'm not sure all of these are actually good things, but they're at least interesting)
undefined
is a reasonably clear signal of intent: you're going to consume the final error or value, and cause a side-effect.fold
wouldn't return another Promise, the caller is assuming responsibility for any failure. An exception that escapes a function passed to fold
could be made fatal (simply by creed's machinery not catching it and letting it hit the VM).then
the outlier.Any thoughts on those?
@briancavalier yeah, those are pretty much my thoughts.
Particularly the first one, if I want to do side-effects, I don't want to have a value.
It looks like there's some precedent for an operation named fold
in fluture and folktale, which in creed's case would return a Promise.
So, maybe we actually want 2 operations here:
Map either side of the promise to a new fulfilled promise:
Promise e a ~> (e -> b) -> (a -> b) -> Promise e b
Consume either side of the promise and perform side effects:
Promise e a ~> (e -> b) -> (a -> b) -> undefined
Any thoughts on those two, and why we'd favor the name fold
for one over the other? And what would we call the other?
FWIW, I'm still in favor of at least the "perform side effects and return undefined" function. I'm possibly in favor of the "map error or value to fulfilled" function, but seems harder to envision use cases for it.
Here's a proposal:
when :: Promise e a ~> (e -> f) -> (a -> b) -> undefined
fulfill(x).when(e => console.error(e), x => console.log(x)) === undefined // logs x
reject(e).when(e => console.error(e), x => console.log(x)) === undefined // logs e
never().when(e => console.error(e), x => console.log(x)) === undefined // doesn't log, ever
when():
From the Bifunctor, it seems a Promise has two states:
I would like to "run" a Promise and act on each state: