Effect CommunityEC
Effect Community2y ago
38 replies
Deleted User

Narrowing Arrays to Tuples Using Match

Suppose we want to write a function that takes an array as input and does different things for certain concrete sizes. Is there a way to narrow from arrays to tuples with Match?

My first thought would be to try something the following this using Match, but the array type doesn't get narrowed correctly, so x and y are inferred to have type number | undefined, leading to a compilation error:
const sumAtMostTwo = (numbers: number[]): number =>
  pipe(
    Match.value(numbers),
    Match.when([], () => 0),
    Match.when([Match.number], ([x]) => x),
    Match.when([Match.number, Match.number], ([x, y]) => x + y),
    Match.orElse(() => {
      throw new Error(`Expected at most 2 elements, got ${numbers.length}`);
    }),
  );


Note that Python has native support for a similar-looking implementation using its built-in pattern matching:
def sum_at_most_two(numbers):
    match numbers:
        case []:
            return 0
        case [x]:
            return x
        case [x, y]:
            return x + y
        case _:
            raise ValueError(f"Expected at most 2 elements, got {len(xs)}")


---

👉 As a note to the maintainers, a couple of proposals have surfaced in the ensuing thread:
- For homogeneous arrays, something like Match.hasLength(2) could narrow from number[] to [number, number] by making use of the fact that number[] & { length: 2 } is equivalent to [number, number] in TypeScript.
- For heterogeneous arrays, a general-purpose Match.tuple utility supporting arbitrary tuples of refinements could be useful, similar to the Predicate.tuple utility that already exists for predicates.
Was this page helpful?