effect 3.14.2 → 3.14.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -359,6 +359,256 @@ export * as Hash from "./Hash.js"
359
359
  export * as HashMap from "./HashMap.js"
360
360
 
361
361
  /**
362
+ * # HashSet
363
+ *
364
+ * An immutable `HashSet` provides a collection of unique values with efficient
365
+ * lookup, insertion and removal. Once created, a `HashSet` cannot be modified;
366
+ * any operation that would alter the set instead returns a new `HashSet` with
367
+ * the changes. This immutability offers benefits like predictable state
368
+ * management and easier reasoning about your code.
369
+ *
370
+ * ## What Problem Does It Solve?
371
+ *
372
+ * `HashSet` solves the problem of maintaining an unsorted collection where each
373
+ * value appears exactly once, with fast operations for checking membership and
374
+ * adding/removing values.
375
+ *
376
+ * ## When to Use
377
+ *
378
+ * Use `HashSet` when you need:
379
+ *
380
+ * - A collection with no duplicate values
381
+ * - Efficient membership testing (**`O(1)`** average complexity)
382
+ * - Set operations like union, intersection, and difference
383
+ * - An immutable data structure that preserves functional programming patterns
384
+ *
385
+ * ## Advanced Features
386
+ *
387
+ * HashSet provides operations for:
388
+ *
389
+ * - Transforming sets with map and flatMap
390
+ * - Filtering elements with filter
391
+ * - Combining sets with union, intersection and difference
392
+ * - Performance optimizations via mutable operations in controlled contexts
393
+ *
394
+ * ## Performance Characteristics
395
+ *
396
+ * - **Lookup** operations ({@link module:HashSet.has}): **`O(1)`** average time
397
+ * complexity
398
+ * - **Insertion** operations ({@link module:HashSet.add}): **`O(1)`** average time
399
+ * complexity
400
+ * - **Removal** operations ({@link module:HashSet.remove}): **`O(1)`** average
401
+ * time complexity
402
+ * - **Set** operations ({@link module:HashSet.union},
403
+ * {@link module:HashSet.intersection}): **`O(n)`** where n is the size of the
404
+ * smaller set
405
+ * - **Iteration**: **`O(n)`** where n is the size of the set
406
+ *
407
+ * The HashSet data structure implements the following traits:
408
+ *
409
+ * - {@link Iterable}: allows iterating over the values in the set
410
+ * - {@link Equal}: allows comparing two sets for value-based equality
411
+ * - {@link Pipeable}: allows chaining operations with the pipe operator
412
+ * - {@link Inspectable}: allows inspecting the contents of the set
413
+ *
414
+ * ## Operations Reference
415
+ *
416
+ * | Category | Operation | Description | Complexity |
417
+ * | ------------ | ----------------------------------- | ------------------------------------------- | ---------- |
418
+ * | constructors | {@link module:HashSet.empty} | Creates an empty HashSet | O(1) |
419
+ * | constructors | {@link module:HashSet.fromIterable} | Creates a HashSet from an iterable | O(n) |
420
+ * | constructors | {@link module:HashSet.make} | Creates a HashSet from multiple values | O(n) |
421
+ * | | | | |
422
+ * | elements | {@link module:HashSet.has} | Checks if a value exists in the set | O(1) avg |
423
+ * | elements | {@link module:HashSet.some} | Checks if any element satisfies a predicate | O(n) |
424
+ * | elements | {@link module:HashSet.every} | Checks if all elements satisfy a predicate | O(n) |
425
+ * | elements | {@link module:HashSet.isSubset} | Checks if a set is a subset of another | O(n) |
426
+ * | | | | |
427
+ * | getters | {@link module:HashSet.values} | Gets an iterator of all values | O(1) |
428
+ * | getters | {@link module:HashSet.toValues} | Gets an array of all values | O(n) |
429
+ * | getters | {@link module:HashSet.size} | Gets the number of elements | O(1) |
430
+ * | | | | |
431
+ * | mutations | {@link module:HashSet.add} | Adds a value to the set | O(1) avg |
432
+ * | mutations | {@link module:HashSet.remove} | Removes a value from the set | O(1) avg |
433
+ * | mutations | {@link module:HashSet.toggle} | Toggles a value's presence | O(1) avg |
434
+ * | | | | |
435
+ * | operations | {@link module:HashSet.difference} | Computes set difference (A - B) | O(n) |
436
+ * | operations | {@link module:HashSet.intersection} | Computes set intersection (A ∩ B) | O(n) |
437
+ * | operations | {@link module:HashSet.union} | Computes set union (A ∪ B) | O(n) |
438
+ * | | | | |
439
+ * | mapping | {@link module:HashSet.map} | Transforms each element | O(n) |
440
+ * | | | | |
441
+ * | sequencing | {@link module:HashSet.flatMap} | Transforms and flattens elements | O(n) |
442
+ * | | | | |
443
+ * | traversing | {@link module:HashSet.forEach} | Applies a function to each element | O(n) |
444
+ * | | | | |
445
+ * | folding | {@link module:HashSet.reduce} | Reduces the set to a single value | O(n) |
446
+ * | | | | |
447
+ * | filtering | {@link module:HashSet.filter} | Keeps elements that satisfy a predicate | O(n) |
448
+ * | | | | |
449
+ * | partitioning | {@link module:HashSet.partition} | Splits into two sets by a predicate | O(n) |
450
+ *
451
+ * ## Notes
452
+ *
453
+ * ### Composability with the Effect Ecosystem:
454
+ *
455
+ * This `HashSet` is designed to work seamlessly within the Effect ecosystem. It
456
+ * implements the {@link Iterable}, {@link Equal}, {@link Pipeable}, and
457
+ * {@link Inspectable} traits from Effect. This ensures compatibility with other
458
+ * Effect data structures and functionalities. For example, you can easily use
459
+ * Effect's `pipe` method to chain operations on the `HashSet`.
460
+ *
461
+ * **Equality of Elements with Effect's {@link Equal `Equal`} Trait:**
462
+ *
463
+ * This `HashSet` relies on Effect's {@link Equal} trait to determine the
464
+ * uniqueness of elements within the set. The way equality is checked depends on
465
+ * the type of the elements:
466
+ *
467
+ * - **Primitive Values:** For primitive JavaScript values like strings, numbers,
468
+ * booleans, `null`, and `undefined`, equality is determined by their value
469
+ * (similar to the `===` operator).
470
+ * - **Objects and Custom Types:** For objects and other custom types, equality is
471
+ * determined by whether those types implement the {@link Equal} interface
472
+ * themselves. If an element type implements `Equal`, the `HashSet` will
473
+ * delegate to that implementation to perform the equality check. This allows
474
+ * you to define custom logic for determining when two instances of your
475
+ * objects should be considered equal based on their properties, rather than
476
+ * just their object identity.
477
+ *
478
+ * ```ts
479
+ * import { Equal, Hash, HashSet } from "effect"
480
+ *
481
+ * class Person implements Equal.Equal {
482
+ * constructor(
483
+ * readonly id: number, // Unique identifier
484
+ * readonly name: string,
485
+ * readonly age: number
486
+ * ) {}
487
+ *
488
+ * // Define equality based on id, name, and age
489
+ * [Equal.symbol](that: Equal.Equal): boolean {
490
+ * if (that instanceof Person) {
491
+ * return (
492
+ * Equal.equals(this.id, that.id) &&
493
+ * Equal.equals(this.name, that.name) &&
494
+ * Equal.equals(this.age, that.age)
495
+ * )
496
+ * }
497
+ * return false
498
+ * }
499
+ *
500
+ * // Generate a hash code based on the unique id
501
+ * [Hash.symbol](): number {
502
+ * return Hash.hash(this.id)
503
+ * }
504
+ * }
505
+ *
506
+ * // Creating a HashSet with objects that implement the Equal interface
507
+ * const set = HashSet.empty().pipe(
508
+ * HashSet.add(new Person(1, "Alice", 30)),
509
+ * HashSet.add(new Person(1, "Alice", 30))
510
+ * )
511
+ *
512
+ * // HashSet recognizes them as equal, so only one element is stored
513
+ * console.log(HashSet.size(set))
514
+ * // Output: 1
515
+ * ```
516
+ *
517
+ * **Simplifying Equality and Hashing with `Data` and `Schema`:**
518
+ *
519
+ * Effect's {@link Data} and {@link Schema `Schema.Data`} modules offer powerful
520
+ * ways to automatically handle the implementation of both the {@link Equal} and
521
+ * {@link Hash} traits for your custom data structures.
522
+ *
523
+ * - **`Data` Module:** By using constructors like `Data.struct`, `Data.tuple`,
524
+ * `Data.array`, or `Data.case` to define your data types, Effect
525
+ * automatically generates the necessary implementations for value-based
526
+ * equality and consistent hashing. This significantly reduces boilerplate and
527
+ * ensures correctness.
528
+ *
529
+ * ```ts
530
+ * import { HashSet, Data, Equal } from "effect"
531
+ * import assert from "node:assert/strict"
532
+ *
533
+ * // Data.* implements the `Equal` traits for us
534
+ * const person1 = Data.struct({ id: 1, name: "Alice", age: 30 })
535
+ * const person2 = Data.struct({ id: 1, name: "Alice", age: 30 })
536
+ *
537
+ * assert(Equal.equals(person1, person2))
538
+ *
539
+ * const set = HashSet.empty().pipe(
540
+ * HashSet.add(person1),
541
+ * HashSet.add(person2)
542
+ * )
543
+ *
544
+ * // HashSet recognizes them as equal, so only one element is stored
545
+ * console.log(HashSet.size(set)) // Output: 1
546
+ * ```
547
+ *
548
+ * - **`Schema` Module:** When defining data schemas using the {@link Schema}
549
+ * module, you can use `Schema.Data` to automatically include the `Equal` and
550
+ * `Hash` traits in the decoded objects. This is particularly important when
551
+ * working with `HashSet`. **For decoded objects to be correctly recognized as
552
+ * equal within a `HashSet`, ensure that the schema for those objects is
553
+ * defined using `Schema.Data`.**
554
+ *
555
+ * ```ts
556
+ * import { Equal, HashSet, Schema } from "effect"
557
+ * import assert from "node:assert/strict"
558
+ *
559
+ * // Schema.Data implements the `Equal` traits for us
560
+ * const PersonSchema = Schema.Data(
561
+ * Schema.Struct({
562
+ * id: Schema.Number,
563
+ * name: Schema.String,
564
+ * age: Schema.Number
565
+ * })
566
+ * )
567
+ *
568
+ * const Person = Schema.decode(PersonSchema)
569
+ *
570
+ * const person1 = Person({ id: 1, name: "Alice", age: 30 })
571
+ * const person2 = Person({ id: 1, name: "Alice", age: 30 })
572
+ *
573
+ * assert(Equal.equals(person1, person2)) // Output: true
574
+ *
575
+ * const set = HashSet.empty().pipe(
576
+ * HashSet.add(person1),
577
+ * HashSet.add(person2)
578
+ * )
579
+ *
580
+ * // HashSet thanks to Schema.Data implementation of the `Equal` trait, recognizes the two Person as equal, so only one element is stored
581
+ * console.log(HashSet.size(set)) // Output: 1
582
+ * ```
583
+ *
584
+ * ### Interoperability with the JavaScript Runtime:
585
+ *
586
+ * To interoperate with the regular JavaScript runtime, Effect's `HashSet`
587
+ * provides methods to access its elements in formats readily usable by
588
+ * JavaScript APIs: {@link values `HashSet.values`},
589
+ * {@link toValues `HashSet.toValues`}
590
+ *
591
+ * ```ts
592
+ * import { HashSet } from "effect"
593
+ *
594
+ * const hashSet: HashSet.HashSet<number> = HashSet.make(1, 2, 3)
595
+ *
596
+ * // Using HashSet.values to convert HashSet.HashSet<A> to IterableIterator<A>
597
+ * const iterable: IterableIterator<number> = HashSet.values(hashSet)
598
+ *
599
+ * console.log(...iterable) // Logs: 1 2 3
600
+ *
601
+ * // Using HashSet.toValues to convert HashSet.HashSet<A> to Array<A>
602
+ * const array: Array<number> = HashSet.toValues(hashSet)
603
+ *
604
+ * console.log(array) // Logs: [ 1, 2, 3 ]
605
+ * ```
606
+ *
607
+ * Be mindful of performance implications (both time and space complexity) when
608
+ * frequently converting between Effect's immutable HashSet and mutable
609
+ * JavaScript data structures, especially for large collections.
610
+ *
611
+ * @module HashSet
362
612
  * @since 2.0.0
363
613
  */
364
614
  export * as HashSet from "./HashSet.js"
@@ -1,4 +1,4 @@
1
- let moduleVersion = "3.14.2"
1
+ let moduleVersion = "3.14.4"
2
2
 
3
3
  export const getCurrentVersion = () => moduleVersion
4
4