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

Array.gen expressions as in Option.gen or Either.gen #3413

Closed
luizgabriel opened this issue Aug 5, 2024 · 1 comment
Closed

Array.gen expressions as in Option.gen or Either.gen #3413

luizgabriel opened this issue Aug 5, 2024 · 1 comment
Labels

Comments

@luizgabriel
Copy link

luizgabriel commented Aug 5, 2024

What is the problem this feature would solve?

Since effect already support Option.gen and Either.gen, why not support Array.gen?

What is the feature you are proposing to solve the problem?

When working with Option, you can:

import { Option } from "effect";

type User = Readonly<{
    name: string;
    email: Option.Option<string>;  
}>

const getUserEmailDomain = (user: User) => Option.gen(function *() {
    const email = yield* user.email;
    const [, domain] = email.split("@");
    return domain;
})

const someUser = Option.some({
    name: "User",
    email: Option.some("[email protected]"),
})

const domain = Option.flatMap(someUser, getUserEmailDomain)

The same applies to Either. Since Array also implements the Monad interface, why not:

import { Array } from "effect";

const cartesianProduct = <A, B>(xs: Array<A>, ys: Array<B>): Array<[A, B]> => Array.gen(function *() {
    const x = yield* xs;
    const y = yield* ys;
    return [x, y];
})

const x: Array<number> = [1, 2];
const y: Array<number> = [3, 4];

const xy = cartesianProduct(x, y); // [ [1, 3], [1, 4], [2, 3], [2, 4] ]

This Array.gen would work the same way as Array.Do with the syntactic conveniences of the generator approach.
syntactic

What alternatives have you considered?

The cartesianProduct example could also be implemented with Array.Do:

const cartesianProduct = <A, B>(xs: Array<A>, ys: Array<B>): Array<[A, B]> => pipe(
    Array.Do,
    Array.bind("x", () => xs),
    Array.bind("y", () => ys),
    Array.map(({ x, y }) => [x, y])
)

Still, I find Array.gen and/or Chunk.gen a good addition to the library.

@luizgabriel luizgabriel added the enhancement New feature or request label Aug 5, 2024
@mikearnaldi
Copy link
Member

That"s a great question but unfortunately there is a key difference between Effect/Option and Array/Stream/Chunk the former are one-shot as in they emit a single value, the latter are multi-shot as in they emit multiple values. Mutable delimited continuations (generators) are only valid to express one-shot effect types, to be able to implement it for multi-shot we would either need an Immutable delimited continuation (not available in JS) or need to replay the generator from scratch (duplicating side effects and introducing a performance bottleneck). For this reason we decided not to implement it.

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

No branches or pull requests

2 participants