diff --git a/.changeset/rich-insects-jog.md b/.changeset/rich-insects-jog.md new file mode 100644 index 0000000000..ed4edfda8d --- /dev/null +++ b/.changeset/rich-insects-jog.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +export Random.make taking hashable values as seed diff --git a/packages/effect/src/Random.ts b/packages/effect/src/Random.ts index 48af9ac255..8f6639a1e3 100644 --- a/packages/effect/src/Random.ts +++ b/packages/effect/src/Random.ts @@ -118,3 +118,12 @@ export const randomWith: (f: (random: Random) => Effect.Effect * @category context */ export const Random: Context.Tag = internal.randomTag + +/** + * Constructs the `Random` service, seeding the pseudo-random number generator + * with an hash of the specified seed. + * + * @since 3.4.9 + * @category constructors + */ +export const make: (seed: A) => Random = internal.make diff --git a/packages/effect/src/internal/defaultServices.ts b/packages/effect/src/internal/defaultServices.ts index bcc2ccda98..f8c6ade906 100644 --- a/packages/effect/src/internal/defaultServices.ts +++ b/packages/effect/src/internal/defaultServices.ts @@ -22,7 +22,7 @@ export const liveServices: Context.Context = pi Context.empty(), Context.add(clock.clockTag, clock.make()), Context.add(console_.consoleTag, console_.defaultConsole), - Context.add(random.randomTag, random.make((Math.random() * 4294967296) >>> 0)), + Context.add(random.randomTag, random.make(Math.random())), Context.add(configProvider.configProviderTag, configProvider.fromEnv()), Context.add(tracer.tracerTag, tracer.nativeTracer) ) diff --git a/packages/effect/src/internal/random.ts b/packages/effect/src/internal/random.ts index 609f2d0417..bb831d7ae1 100644 --- a/packages/effect/src/internal/random.ts +++ b/packages/effect/src/internal/random.ts @@ -2,6 +2,7 @@ import * as Chunk from "../Chunk.js" import * as Context from "../Context.js" import type * as Effect from "../Effect.js" import { pipe } from "../Function.js" +import * as Hash from "../Hash.js" import type * as Random from "../Random.js" import * as PCGRandom from "../Utils.js" import * as core from "./core.js" @@ -85,4 +86,4 @@ const swap = (buffer: Array, index1: number, index2: number): Array => return buffer } -export const make = (seed: number): Random.Random => new RandomImpl(seed) +export const make = (seed: A): Random.Random => new RandomImpl(Hash.hash(seed)) diff --git a/packages/effect/test/Random.test.ts b/packages/effect/test/Random.test.ts index b4fad2a5bc..5bcf690a09 100644 --- a/packages/effect/test/Random.test.ts +++ b/packages/effect/test/Random.test.ts @@ -1,4 +1,4 @@ -import { Array, Chunk, Effect, Random } from "effect" +import { Array, Chunk, Data, Effect, Random } from "effect" import * as it from "effect/test/utils/extend" import { assert, describe } from "vitest" @@ -10,4 +10,19 @@ describe("Random", () => { assert.isTrue(Chunk.every(end, (n) => n !== undefined)) assert.deepStrictEqual(start.sort(), Array.fromIterable(end).sort()) }).pipe(Effect.repeatN(100))) + + it.effect("make", () => + Effect.gen(function*() { + const random0 = Random.make("foo") + const random1 = Random.make("foo") + const random2 = Random.make(Data.struct({ foo: "bar" })) + const random3 = Random.make(Data.struct({ foo: "bar" })) + const n0 = yield* random0.next + const n1 = yield* random1.next + const n2 = yield* random2.next + const n3 = yield* random3.next + assert.strictEqual(n0, n1) + assert.strictEqual(n2, n3) + assert.notStrictEqual(n0, n2) + })) })