Open xaviervia opened 7 years ago
So...
1) Using chain/flatMap is not required for users of middleware. This is just the initial example I've pushed, in the next iteration the json middleware will be just json()
, since it makes sense than middleware doesn't leave this job to the user, since using map
would result in a wrong usage. Of course, the creator of a middleware needs to understand what to do;
2) "I understand Folktale does not provide any such monad for continuous values". It will, but flyd
really works fine, and it's dead simple.
3) Yes, it's unfortunate that the libs use different names: chain
& flatMap
, maybe we could reexport new ones for convenience.
4) I'm not sure we can avoid the double call in any way. Note map/map, chain/map, map/chain, chain/chain have completely different meanings:
Note there's also mapError
, cata
and other methods that can be used in the Result and also filter
, throttle
etc, that can be used on the Stream. To create an API with all combinations seem overkill.
I'll publish some new stuff soon and I guess this will be clearer.
I guess the point with trying to avoid the double map
is that there is no really a point in mapping over a failing value, right? In a rejected Task, the rejection gets "fast tracked" avoiding all further calls to .chain
and .map
. I imagined that the same could apply here: having some continuous value construct that includes the Ok/Error status as part of it, so essentially Stream.Error would be a constructor of Stream, and if you want to indicate failure, you do so by chaining and rejecting in the chained Stream.
Trying to come up with an example of what I’m suggesting I end up realizing I just want to chain tasks, so the implied question is: why using a stream instead of a task?
1) Mmm, maybe I don't get it, but definitively are needs to map over failing values, both to recover and to emit errors to the client.
2) Check the repo now, there's even some docs published at joaomilho.github.io/zealot, very basic and incomplete.
3) On the Stream vs Task, think about this issue:
const delay = (value, seconds) =>
Promise.new((resolve) =>
setTimeout(resolve(value), seconds * 1000))
delay('OK', 5000).then(console.log)
// 5s after... 'OK'
This is a classic use case for a Promise/Task. Now rewrite the same using setInterval
, where you can get a console log of 'OK' every 5 seconds.
I guess we can discuss here as good as via chat or better. I started playing around with building an example, and what struck me first was that it's a little unclear why it's necessary the
result.chain
in every middleware. I do understand why, but it took me reading through all the code to do it, so I guess it is something that could be documented.Also, I understand why we
flatMap
and alsochain
: one is for the Stream, the other for the Result inside the stream. But it makes me queasy. In Task, for example, the Task can be rejected at any time and a rejected Task is pretty much like aResult.Error
, there are even natural transformations for them… would it be possible to just use Streams which supportOk
andError
constructors as well? That way, middlewares will justchain
/flatMap
only once. Same for mapping.Just for illustration purposes, here is how my example looks due to the double
map
needed to get out of theStream
andResult
:I understand Folktale does not provide any such monad for continuous values, less so for values that can have individual failing status. I don’t have any suggestions about what to do, but flattening it into a single structure that you can just
map
andchain
upon would be really nice to make it easy to understand.