I wonder if it's worth consolidating a common stack, something like
type ReaderTaskEither<E, L, A> = (e: E) => TaskEither<L, A>
I'm only in the middle of integration of fp-ts into our codebase. We are using Option, Either and some custom ADTs right now. The plans are to use Validation also.
@raveclassic I mean when you have to nest monads, let me show you an example.
Say you have a simple API like this
import { Task } from 'fp-ts/lib/Task'
import axios from 'axios'
/** If successful, returns the invoice id */
const purchase1 = (userId: string, productId: string): Task<string> =>
new Task(() => axios.post(`https://mysite/api/user/${userId}/purchase/${productId}`, {}).then(res => res.data))
There's no error handling though, so you switch to TaskEither (already consolidated in fp-ts)
type PurchaseError = { type: 'UserNotFound' } | { type: 'ProductNotFound' } | { type: 'PurchaseNotAllowed' }
import { TaskEither, tryCatch } from 'fp-ts/lib/TaskEither'
const purchase2 = (userId: string, productId: string): TaskEither<PurchaseError, string> =>
tryCatch<PurchaseError, string>(
() => axios.post(`https://mysite/api/user/${userId}/purchase/${productId}`, {}).then(res => res.data),
reason => {
// error handling here...
return { type: 'PurchaseNotAllowed' }
}
)
The url is hard-coded though, and here it comes ReaderTaskEither
class ReaderTaskEither<E, L, A> {
constructor(readonly run: (e: E) => TaskEither<L, A>) {}
/* ... */
}
type AppConfig = {
apiRoot: string
}
const purchase3 = (userId: string, productId: string): ReaderTaskEither<AppConfig, PurchaseError, string> =>
new ReaderTaskEither(config =>
tryCatch<PurchaseError, string>(
() => axios.post(`${config.apiRoot}/user/${userId}/purchase/${productId}`, {}).then(res => res.data),
// ^ no more hard-coded
reason => {
// error handling here...
return { type: 'PurchaseNotAllowed' }
}
)
)
purchase3('123', '456')
.run({ apiRoot: 'https://mysite/api' })
.value.run()
.then(e => e.fold(error => console.error(error), invoiceId => console.log(invoiceId)))
A reference implementation ReaderTaskEither
That s an interesting question and to be honnest, i ve not introduced yet monad transformers to the team.
I ll do it but i m lurking at the different task/io libraries out there..
I m concerned about correctness, performance and leaks and know there s a lot of efforts in funfix atm.
Also i ve not checked (i m late on it) how well or not fp-ts and funfix integrate with each other (diff hkt impl may be a show stopper)
I m concerned about correctness, performance and leaks and know there s a lot of efforts in funfix atm
@sledorze that's interesting and something I would like to dig deeper into, could you please point me to some resources?
how well or not fp-ts and funfix integrate with each other
Not sure, that's interesting as well. I'll do some experiments and open a new issue
@gcanti you may find some insight on his creator (alex) blog: https://alexn.org/blog/2017/10/11/javascript-promise-leaks-memory.html
For information he his also behind the Monix library in Scala.
Heres the gitter ofthe project: https://gitter.im/funfix/funfix
Basically my beliefs are based on this guy, what he has achieved and his willing to replicate that on node/browser.
And to replicate his words:
alexelcu [3:38 PM]
I don鈥檛 have numbers yet. `IO` is a port of Monix Task, which is currently the fastest implementation for Scala (versus Cats IO, FS2 and Scalaz 7) and so this `IO` has a really good encoding.
If it鈥檚 not amongst the fastest, then I鈥檒l treat that as a bug that needs to be fixed.
About performance you can get some infos from here (execution strategies):
https://github.com/funfix/funfix/pull/37
That may be a good start.
@gcanti Ok I'm starting to use a stack based on futureEither and readerFutureEither (Future from funfix) - derived from the advices you gave.
It works very well.
Not sure if it could belong to that repo anyway as it would create a non desirable dependency.
It works very well
@sledorze really glad to hear that: I tried to build fp-ts so it can be expanded, as I did with fp-ts-fluture or fp-ts-rxjs, your move to funfix is a good proof of that
Not sure if it could belong to that repo anyway
Maybe you could publish a package
But since, ReaderTaskEither implements Monad3, we can't use it in the MTL example.
Is there any workaround for this? @gcanti
@RPallas92 with more overloadings (alas doing MTL-style in TypeScript is super verbose) see https://github.com/gcanti/fp-ts/pull/410
Most helpful comment
@raveclassic I mean when you have to nest monads, let me show you an example.
Say you have a simple API like this
There's no error handling though, so you switch to
TaskEither(already consolidated in fp-ts)The url is hard-coded though, and here it comes
ReaderTaskEither