I can't understand why the following code doesn't work. The types all seem to be correct
const likeArticle = flow(
api.likeArticle,
setArticleLike,
chain(updateLikedArticlesCount)
);
The above functions have the following signatures:
likeArticle: (id?: number | undefined) => TaskEither<undefined, number>
const setArticleLike: (ma: TaskEither<undefined, number>) => TaskEither<undefined, Article>
chain<undefined, Article, Article>(f: (a: Article) => TaskEither<undefined, Article>): (ma: TaskEither<undefined, Article>) => TaskEither<undefined, Article>
updateLikedArticlesCount: (article: Article) => TaskEither<undefined, Article>
I am trying to call it as likeArticle(1) for example but all it returns is a chain function rather than a TaskEither.
I can use pipe as follows:
const likeArticle = (id?: number) =>
pipe(api.likeArticle(id), setArticleLike, chain(updateLikedArticlesCount))();
But seems like I should be able to pass id into the pipe someway rather than needing this outside wrapping function.
@rikbrowning FYI you can use declare in order to write a repro:
import { flow } from 'fp-ts/lib/function'
import { chain, TaskEither } from 'fp-ts/lib/TaskEither'
type Article = string
declare const likeArticle: (id?: number) => TaskEither<undefined, number>
declare const setArticleLike: (ma: TaskEither<undefined, number>) => TaskEither<undefined, Article>
declare const updateLikedArticlesCount: (article: Article) => TaskEither<undefined, Article>
// program: (id?: number) => TaskEither<undefined, string>
const program = flow(likeArticle, setArticleLike, chain(updateLikedArticlesCount))
@gcanti TIL, that's really cool. Sorry you'll have to forgive my ignorance
@rikbrowning no problem, that's kind of a hack but it works well.
Back to this issue, can we close it? looks like program has the expected type.
@gcanti it has the expected type but when I execute it I get back function chain rather than a TaskEither?
Weird, if I add the implementations I can see the expected result
import { flow } from 'fp-ts/lib/function'
import { chain, right, TaskEither } from 'fp-ts/lib/TaskEither'
type Article = string
const likeArticle = (_id?: number): TaskEither<undefined, number> => right(1)
const setArticleLike = (_ma: TaskEither<undefined, number>): TaskEither<undefined, Article> => right('a')
const updateLikedArticlesCount = (article: Article): TaskEither<undefined, Article> => right(article)
flow(likeArticle, setArticleLike, chain(updateLikedArticlesCount))(1)().then(console.log)
// { _tag: 'Right', right: 'a' }
flow(likeArticle, setArticleLike, chain(updateLikedArticlesCount))(1)() is that not the equivalent of program(1)()? Is there no way to have the call behave as program(1) without extra function call? Ideally I want to expose the flow function to accept the ID without having to the wrapper.
After some more reading, is the extra () required to execute the TaskEither?
is the extra () required to execute the TaskEither?
Yes if you want to get back a promise, TaskEither<E, A> is just an alias of () => Promise<Either<E, A>>
Awesome, that's the part that was confusing me
It should be explained in the documentation why IO, Task, TaskEither need to be called. Something like: Side-effect composition can be called now or later. In FP, we split definition from execution. Am I correct?
Most helpful comment
@rikbrowning FYI you can use
declarein order to write a repro: