Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change Writer definition and remove Tuple2 module in favour of Writer #1767

Open
wants to merge 4 commits into
base: 3.0.0
Choose a base branch
from

Conversation

gcanti
Copy link
Owner

@gcanti gcanti commented Sep 9, 2022

No description provided.

*
* @since 3.0.0
*/
export const mapFst: Functor2<URI>['map'] = map
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 How useful is it really to have these aliases? That made good amount of sense for Tuple2 to be named fst and snd for the correlation to a data structure which has a first and second index, but it feels misplaced for Writer since it's an effect, which just so happens to be encoded as a Tuple2

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, however I propose to identify Writer<W, A> with [A, W] as a design choice, like TaskEither<E, A> is Task<Either<E, A>> as a design choice.

For example I often see people asking: "how can I convert a TaskEither<E, A> into a Task<Either<E, A>>?" There's no helper for that in fp-ts because TaskEither<E, A> already is Task<Either<E, A>> by design.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a risk that by embracing these implementation details we're making breaking changes hard or even impossible to make.

A problem I've observed in the real world is that IO, Lazy, and old () => A functions are the same to the type system. This issue is somewhat extended to Reader when you're only touching the output. You'd ideally want a type error when you mistakenly mix these, but at present it's up to the user to notice.

import { pipe } from 'fp-ts/function'
import * as Lazy from 'fp-ts-std/Lazy'

declare const f: Lazy<number>
declare const g: (n: number) => IO<number>

// Hidden side effect at `g`
const x: Lazy<number> = pipe(f, Lazy.chain(g))

This is more broadly an issue with how you can execute effects like IO and Task as ordinary nullary function application. This is great for adoption but as a team and codebase scale it starts to become a problem as it obscures where effects are happening.

This can be solved by encoding these types as newtypes, but not if the entire ecosystem relies upon their subtyping relationships.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants