Effect-TS / effect

An ecosystem of tools for building production-grade applications in TypeScript.
https://effect.website
MIT License
7.04k stars 222 forks source link

From Discord: When generating recursive arbitraries #3512

Closed effect-bot closed 1 week ago

effect-bot commented 2 weeks ago

Summary

Summary

  1. Initial Inquiry: The user spaethnl asked about limiting the amount of nesting or the total number of schemas instantiated when generating arbitraries, particularly for a recursive schema to prevent infinite schemas.
  2. Clarification: datner_ clarified that arbitraries don't generate schemas and suggested checking the fast-check documentation.
  3. Further Details: spaethnl elaborated on trying to pass depthFactor and depthSize into a schema's arbitrary interface or applying createDepthIdentifier to a schema. They also considered using a custom arbitrary handler.
  4. Acknowledgment: datner_ admitted to not understanding the technical details but encouraged posting any improvement suggestions to their repository.
  5. Technical Suggestion: timsmart suggested using the fc.letrec API to create recursive structures and referenced the causeArbitrary in the effect schema source.
  6. Example Provided: spaethnl shared a link to a demonstration of the issue and mentioned the challenge of incorporating fc.letrec into a more complex schema without copying the go function from Arbitrary.
  7. Specific Issue: The problem arises when a schema has both a required recursive array (which can be empty) and any other recursive field.

Key Takeaways

Discord thread

https://discord.com/channels/795981131316985866/1278090821287284746

nspaeth commented 2 weeks ago

See The playground for a demonstration.

jessekelly881/effect-schema-compilers/blob/main/src/faker.ts has incorporated an option for this for fakerjs, which might be a nice way to handle it here. Alternatively, passing the Artibrary.ts/go function and current arguments to the arbitrary handler might work as well, and provide more flexibility.

(As an aside, but probably a different issue, built-in integration with faker might be nice. I currently use this for some arbitraries:

import { faker, Faker } from '@faker-js/faker'
import { FastCheck } from '@effect/schema'
export const fakerToArb = <A>(fakerGen: (faker: Faker) => A) =>
  () => (fc: typeof FastCheck) => {
    return fc
      .noShrink(
        // shrink on a seed makes no sense
        fc.noBias(
          // same probability to generate each of the allowed integers
          fc.integer(),
        ),
      )
      .map((seed) => {
        faker.seed(seed); // seed the generator
        return fakerGen(faker); // call it
      });
  };
gcanti commented 2 weeks ago

See The playground for a demonstration

@nspaeth It's me or ^ this just shows the default code?

nspaeth commented 2 weeks ago

Not sure what happened. I fixed the link!

nspaeth commented 2 weeks ago

@gcanti I've updated the playground to include a case with recursive Maps:

https://effect.website/play#d9fc7016fd32

gcanti commented 1 week ago

@nspaeth I get an "Application error" now, better to paste the repros here I guess

nspaeth commented 1 week ago

All of my links seem to have stopped working. There seems to be some bug in the playground, as I double checked them all when updating them after you initially couldn't access them.

I don't have a local copy of the repro.

IMax153 commented 1 week ago

There seems to be some bug in the playground

This should now be fixed. Apologies for the inconvenience!

gcanti commented 1 week ago

@nspaeth PR here https://github.com/Effect-TS/effect/pull/3560

(you can try it out by running pnpm add https://pkg.pr.new/Effect-TS/effect/@effect/schema@f7008f7)