Skip to content
Agentmart
Submit a tool

effect-data

Effect 4 data types, equality, caching and batching.

Skill by andabove

IndexedMIT
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/andabove-effect-data

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Effect 4 data types, equality, caching and batching. Use when choosing or using Option, Result, Duration, DateTime, BigDecimal, Redacted, Chunk, HashMap or HashSet; when defining value classes or tagged unions with Data; when comparing or sorting with Equal, Equivalence or Order; when memoizing an effect with Effect.cached or Cache; or when batching lookups with Request and RequestResolver.

Use cases: data

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/effect-data

What's inside

Skill name
effect-data
Description
Effect 4 data types, equality, caching and batching. Use when choosing or using Option, Result, Duration, DateTime, BigDecimal, Redacted, Chunk, HashMap or HashSet; when defining value classes or tagged unions with Data; when comparing or sorting with Equal, Equivalence or Order; when memoizing an effect with Effect.cached or Cache; or when batching lookups with Request and RequestResolver.
License
MIT
Instructions
247 lines in SKILL.md · view on GitHub

Files (5)

  • SKILL.md
  • effect-data-caching-batching.md · references/
  • effect-data-collections.md · references/
  • effect-data-equality.md · references/
  • effect-data-time.md · references/

SKILL.md (first lines)

# Effect data types

Checked against `effect 4.0.0`. When the project has a newer version, read `node_modules/effect/src/<Module>.ts` for the API and `node_modules/effect/AGENTS.md` for the maintainers' guidance before you trust a name here. The source wins over this skill and over the website.

Import each module from its own subpath, as every example here does: `import * as Option from "effect/Option"`. Import the `Array` module as `Arr` (`import * as Arr from "effect/Array"`) so it does not shadow the global `Array`.

## Pick the type

| You have | Use | Reason |
| --- | --- | --- |
| A value that can be absent, and the absence flows through more logic | `Option<A>` | `map`, `flatMap`, `Option.gen` and `Effect.fromOption` compose it. Keep `A \| undefined` on JSON fields and convert at the edge. |
| A pure computation that succeeds with `A` or fails with `E` | `Result<A, E>` | Effect 4 name for Effect 3 `Either`. Inside an effect, use the error channel instead. |
| The outcome of a run, with defects and interruption | `Exit` and `Cause` | See [effect-errors](skill:effect-errors). |
| A span of time | `Duration` | Effect APIs that take a time (`Effect.sleep`, `Effect.timeout`, `Schedule`, cache TTLs) accept `Duration.Input`, such as `"5 seconds"`. |
| A point in time | `DateTime` | `DateTime.now` reads the `Clock`, so tests control it. Use it in place of `Date` and `Date.now()`. |
| Money or another exact decimal | `BigDecimal` | `0.1 + 0.2` is `0.30000000000000004` as a `number`, and `0.3` as a `BigDecimal`. |
| A secret | `Redacted<A>` | Prints as `<redacted>` in `String`, `JSON.stringify` and every built-in logger. |
| A list | `ReadonlyArray` and the `Arr` module | Streams, sinks and `Stream.runCollect` use arrays in Effect 4. Reach for `Chunk` only for many appends or prepends, or where an API takes one (`Schema.Chunk`, `TxChunk`). |
| A map or set keyed by value, not by reference | `HashMap`, `HashSet` | They compare keys with `Equal.equals`. Native `Map` and `Set` compare by reference. |
| A value type with methods, or a tagged union | `Data.Class`, `Data.TaggedClass`, `Data.taggedEnum` | Constructor from one record, structural equality. Use `Schema.Class` when it crosses a boundary ([effect-schema](skill:effect-schema)). |
| An error type | `Schema.TaggedError` or `Data.TaggedError` | See [effect-errors](skill:effect-errors). |
| A comparison or sort by a field | `Equivalence`, `Order` | Derive from a base with `mapInput`, combine with `combine`. |
| An effect to run once and reuse | `Effect.cached`, `Effect.cachedWithTTL` | Section [Caching](#caching). |
| A lookup to memoize per key | `Cache` | Section [Caching](#caching). |
| Many small lookups to send as one call | `Request`, `RequestResolver`, `Effect.request` | Section [Batching](#batching). |

## Effect 3 names that changed

Code written from Effect 3 memory uses these names. They do not exist in 4.0.0.

| Effect 3 | Effect 4.0.0 |
| --- | --- |
| `Either`, `Either.right`, `Either.left`, `.right`, `.left` | `Result`, `Result.succeed`, `Result.fail`, `.success`, `.failure` (tags `"Success"`, `"Failure"`) |
| `Effect.either` | `Effect.result` |
| `Option.fromNullable` | `Option.fromNullishOr` (also `fromUndefinedOr`, `fromNullOr`) |
| `Option.getEquivalence`, `Option.getOrder` | `Option.makeEquivalence`, `Option.makeOrder` |
| `unsafeX` (`DateTime.unsafeMake`, `Chunk.unsafeFromArray`, `Redacted.unsafeWipe`) | `xUnsafe` (`DateTime.makeUnsafe`, `Chunk.fromArrayUnsafe`, `Redacted.wipeUnsafe`) |
| `Duration.decode`, `DurationInput` | `Duration.fromInputUnsafe` (throws) or `Duration.fromInput` (returns `Option`), `Duration.Input` |
| `Data.struct`, `Data.tuple`, `Data.array`, `Data.case`, `Data.tagged` | Plain objects and arrays; `Equal.equals` compares them by value now |
| `Order.reverse` | `Order.flip` |
| `RequestResolver.makeBatched` | `RequestResolver.make` |
| `Effect.withRequestBatching`, `Effect.withRequestCaching`, `{ batching: true }` | Gone. Batching follows concurrency; caching is `RequestResolver.withCache` or `RequestResolver.asCache` |
| `List`, `SortedMap`, `SortedSet` modules | Gone. Use `ReadonlyArray`, or `HashMap` and sort with `Order` on read |

## Option and Result

```ts
import * as Effect from "effect/Effect"
import * as Option from "effect/Option"
import * as Result from "effect/Result"

interface User {
  readonly id: string
  readonly managerId: string | undefined
}
declare const users: ReadonlyMap<string, User>

const findUser = (id: string): Option.Option<User> => Option.fromNullishOr(users.get(id))

const findManager = (id: string): Option.Option<User> =>
  findUser(id).pipe(
    Option.flatMap((user) => Option.fromNullishOr(user.managerId)),
    Option.flatMap(findUser)
  )

const parsePort = (raw: string): Result.Result<number, string> => {
  const port = Number(raw)
  return Number.isInteger(port) && port > 0 && port < 65536
    ? Result.succeed(port)
    : Result.fail(`invalid port: ${raw}`)
}

export const program = Effect.gen(function*() {
  // None fails with Cause.NoSuchElementError
  const manager = yield* Effect.fromOption(findManager("u-1"))
  // Failure fails with its error, here a string
  const port = yield* Effect.fromResult(parsePort("8080"))
  return { manager: manager.id, port }
})
```

- Convert with `Effect.fromOption` and `Effect.fromResult` before you `yield*` inside `Effect.gen`. In 4.0.0 an `Option` or `Result` is not an `Effect`: `yield* Option.some(1)` in `Effect.gen` is a type error and dies at runtime with "Not a valid effect". The website's Option and Result pages say otherwise; they are wrong for 4.0.0. `Exit` is an `Effect` and yields directly.
- Turn a failure into a value with `Effect.option` (drops the error) or `Effect.result` (keeps it).
- Use `Option.gen` and `Result.gen` for pure code only. They stop at the first `None` or `Failure`.
- Leave the boundary with `Option.getOrUndefined`, `Option.getOrElse(() => fallback)`, `Option.match` or `Result.match({ onSuccess, onFailure })`. Use `getOrThrow` only where a missing value is a bug.
- Combine many with `Option.all` and `Result.all` (tuple, struct or iterable). `Result.all` stops at the first failure; to keep every failure, `Arr.partition(inputs, parse)` returns `[successes, failures]` for a `parse` that returns a `Result`.

## Equality

`Equal.equals` compares by value by default in Effect 4: plain objects, arrays, `Map`, `Set`, `Date`, `RegExp`, typed arrays and class instances, deeply. `HashMap`, `HashSet`, `Data.*` and `Option` all use it.

```ts
import * as Equal from "effect/Equal"
import * as Hash from "effect/Hash"
import * as HashSet from "effect/HashSet"

HashSet.size(HashSet.make({ sku: "A1" }, { sku: "A1" })) // 1
new Set([{ sku: "A1" }, { sku: "A1" }]).size // 2: native Set compares by reference

// Equality on part of a value: implement Equal and a Hash that agrees with it
class Account implements Equal.Equal {
  constructor(readonly id: string, readonly lastSeen: Date) {}
  [Equal.symbol](that: Equal.Equal): boolean {
    return that instanceof Account && this.id === that.id
  }
  [Hash.symbol](): number {
    return Hash.string(this.id)
  }
}

HashSet.size(HashSet.make(new Account("a", new Date(1)), new Account("a", new Date(2)))) // 1
```

- Treat a value as frozen once it has been compared, hashed or used as a key. `Equal.equals` caches the result per pair of objects (`Date` included), and `Hash.hash` caches the hash of each plain object, array, `Map` and `Set` (not `Date` or `RegExp`), so a later mutation is not seen: once `Equal.equals(c, d)` has returned `true`, it still returns `true` after `c.n = 2`.
- Tell types apart with a `_tag` field. For plain classes, equality checks own and prototype keys and their values, not the class: instances of two classes with the same fields and no methods are equal to each other and to a plain object with those fields. A `Data.Class` instance never equals a plain object, and two different `Schema.Class` classes with the same fields are not equal.
- Opt one object out of structural comparison with `Equal.byReference(obj)` (returns a proxy) or `Equal.byReferenceUnsafe(obj)` (marks the object).
- `===` stays reference equality. Use `Equal.equals` when you mean value equality.

`Data.Class`, `Data.TaggedClass` and `Data.taggedEnum` give a constructor from one record and the same structural equality. Use `taggedEnum` for a union with `$is` and `$match`. The details and examples are in [the equality reference](references/effect-data-equality.md).

From andabove/skills, MIT.

More from andabove/skills

Signals

Stars
0
Forks
0
Open issues
0
Last commit (this folder)
Oct 3, 2026 (26 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from andabove

Cite this page

effect-data skill. Agent Mart. https://agentmart.dev/skills/andabove-effect-data (last updated 2026-10-24)