Skip to content

Commit

Permalink
Simplify internal/cause.ts by using the internal Option.mergeWith (
Browse files Browse the repository at this point in the history
  • Loading branch information
gcanti authored Jan 31, 2025
1 parent 72f09dc commit aa26d9b
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 135 deletions.
15 changes: 15 additions & 0 deletions packages/effect/src/Option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2162,3 +2162,18 @@ export const gen: Gen.Gen<OptionTypeLambda, Gen.Adapter<OptionTypeLambda>> = (..
}
return some(state.value)
}

/**
* Merges two optional values, applying a function if both exist.
* Unlike {@link zipWith}, this function returns `None` only if both inputs are `None`.
*
* @internal
*/
export const mergeWith = <A>(f: (a1: A, a2: A) => A) => (o1: Option<A>, o2: Option<A>): Option<A> => {
if (isNone(o1)) {
return o2
} else if (isNone(o2)) {
return o1
}
return some(f(o1.value, o2.value))
}
169 changes: 34 additions & 135 deletions packages/effect/src/internal/cause.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,34 +259,12 @@ export const dieOption = <E>(self: Cause.Cause<E>): Option.Option<unknown> =>
/** @internal */
export const flipCauseOption = <E>(self: Cause.Cause<Option.Option<E>>): Option.Option<Cause.Cause<E>> =>
match(self, {
onEmpty: Option.some(empty),
onFail: (failureOption) => pipe(failureOption, Option.map(fail)),
onEmpty: Option.some<Cause.Cause<E>>(empty),
onFail: Option.map(fail),
onDie: (defect) => Option.some(die(defect)),
onInterrupt: (fiberId) => Option.some(interrupt(fiberId)),
onSequential: (left, right) => {
if (Option.isSome(left) && Option.isSome(right)) {
return Option.some(sequential(left.value, right.value))
}
if (Option.isNone(left) && Option.isSome(right)) {
return Option.some(right.value)
}
if (Option.isSome(left) && Option.isNone(right)) {
return Option.some(left.value)
}
return Option.none()
},
onParallel: (left, right) => {
if (Option.isSome(left) && Option.isSome(right)) {
return Option.some(parallel(left.value, right.value))
}
if (Option.isNone(left) && Option.isSome(right)) {
return Option.some(right.value)
}
if (Option.isSome(left) && Option.isNone(right)) {
return Option.some(left.value)
}
return Option.none()
}
onSequential: Option.mergeWith(sequential),
onParallel: Option.mergeWith(parallel)
})

/** @internal */
Expand All @@ -298,68 +276,24 @@ export const interruptOption = <E>(self: Cause.Cause<E>): Option.Option<FiberId.

/** @internal */
export const keepDefects = <E>(self: Cause.Cause<E>): Option.Option<Cause.Cause<never>> =>
match<Option.Option<Cause.Cause<never>>, E>(self, {
match(self, {
onEmpty: Option.none(),
onFail: () => Option.none(),
onDie: (defect) => Option.some(die(defect)),
onInterrupt: () => Option.none(),
onSequential: (left, right) => {
if (Option.isSome(left) && Option.isSome(right)) {
return Option.some(sequential(left.value, right.value))
}
if (Option.isSome(left) && Option.isNone(right)) {
return Option.some(left.value)
}
if (Option.isNone(left) && Option.isSome(right)) {
return Option.some(right.value)
}
return Option.none()
},
onParallel: (left, right) => {
if (Option.isSome(left) && Option.isSome(right)) {
return Option.some(parallel(left.value, right.value))
}
if (Option.isSome(left) && Option.isNone(right)) {
return Option.some(left.value)
}
if (Option.isNone(left) && Option.isSome(right)) {
return Option.some(right.value)
}
return Option.none()
}
onSequential: Option.mergeWith(sequential),
onParallel: Option.mergeWith(parallel)
})

/** @internal */
export const keepDefectsAndElectFailures = <E>(self: Cause.Cause<E>): Option.Option<Cause.Cause<never>> =>
match<Option.Option<Cause.Cause<never>>, E>(self, {
match(self, {
onEmpty: Option.none(),
onFail: (failure) => Option.some(die(failure)),
onDie: (defect) => Option.some(die(defect)),
onInterrupt: () => Option.none(),
onSequential: (left, right) => {
if (Option.isSome(left) && Option.isSome(right)) {
return Option.some(sequential(left.value, right.value))
}
if (Option.isSome(left) && Option.isNone(right)) {
return Option.some(left.value)
}
if (Option.isNone(left) && Option.isSome(right)) {
return Option.some(right.value)
}
return Option.none()
},
onParallel: (left, right) => {
if (Option.isSome(left) && Option.isSome(right)) {
return Option.some(parallel(left.value, right.value))
}
if (Option.isSome(left) && Option.isNone(right)) {
return Option.some(left.value)
}
if (Option.isNone(left) && Option.isSome(right)) {
return Option.some(right.value)
}
return Option.none()
}
onSequential: Option.mergeWith(sequential),
onParallel: Option.mergeWith(parallel)
})

/** @internal */
Expand All @@ -370,34 +304,18 @@ export const linearize = <E>(self: Cause.Cause<E>): HashSet.HashSet<Cause.Cause<
onDie: (defect) => HashSet.make(die(defect)),
onInterrupt: (fiberId) => HashSet.make(interrupt(fiberId)),
onSequential: (leftSet, rightSet) =>
pipe(
leftSet,
HashSet.flatMap((leftCause) =>
pipe(
rightSet,
HashSet.map((rightCause) => sequential(leftCause, rightCause))
)
)
),
HashSet.flatMap(leftSet, (leftCause) => HashSet.map(rightSet, (rightCause) => sequential(leftCause, rightCause))),
onParallel: (leftSet, rightSet) =>
pipe(
leftSet,
HashSet.flatMap((leftCause) =>
pipe(
rightSet,
HashSet.map((rightCause) => parallel(leftCause, rightCause))
)
)
)
HashSet.flatMap(leftSet, (leftCause) => HashSet.map(rightSet, (rightCause) => parallel(leftCause, rightCause)))
})

/** @internal */
export const stripFailures = <E>(self: Cause.Cause<E>): Cause.Cause<never> =>
match(self, {
onEmpty: empty,
onFail: () => empty,
onDie: (defect) => die(defect),
onInterrupt: (fiberId) => interrupt(fiberId),
onDie: die,
onInterrupt: interrupt,
onSequential: sequential,
onParallel: parallel
})
Expand All @@ -406,51 +324,32 @@ export const stripFailures = <E>(self: Cause.Cause<E>): Cause.Cause<never> =>
export const electFailures = <E>(self: Cause.Cause<E>): Cause.Cause<never> =>
match(self, {
onEmpty: empty,
onFail: (failure) => die(failure),
onDie: (defect) => die(defect),
onInterrupt: (fiberId) => interrupt(fiberId),
onSequential: (left, right) => sequential(left, right),
onParallel: (left, right) => parallel(left, right)
onFail: die,
onDie: die,
onInterrupt: interrupt,
onSequential: sequential,
onParallel: parallel
})

/** @internal */
export const stripSomeDefects = dual<
(pf: (defect: unknown) => Option.Option<unknown>) => <E>(self: Cause.Cause<E>) => Option.Option<Cause.Cause<E>>,
<E>(self: Cause.Cause<E>, pf: (defect: unknown) => Option.Option<unknown>) => Option.Option<Cause.Cause<E>>
>(2, <E>(self: Cause.Cause<E>, pf: (defect: unknown) => Option.Option<unknown>) =>
match(self, {
onEmpty: Option.some(empty),
onFail: (error) => Option.some(fail(error)),
onDie: (defect) => {
const option = pf(defect)
return Option.isSome(option) ? Option.none() : Option.some(die(defect))
},
onInterrupt: (fiberId) => Option.some(interrupt(fiberId)),
onSequential: (left, right) => {
if (Option.isSome(left) && Option.isSome(right)) {
return Option.some(sequential(left.value, right.value))
}
if (Option.isSome(left) && Option.isNone(right)) {
return Option.some(left.value)
}
if (Option.isNone(left) && Option.isSome(right)) {
return Option.some(right.value)
}
return Option.none()
},
onParallel: (left, right) => {
if (Option.isSome(left) && Option.isSome(right)) {
return Option.some(parallel(left.value, right.value))
}
if (Option.isSome(left) && Option.isNone(right)) {
return Option.some(left.value)
}
if (Option.isNone(left) && Option.isSome(right)) {
return Option.some(right.value)
}
return Option.none()
}
}))
>(
2,
<E>(self: Cause.Cause<E>, pf: (defect: unknown) => Option.Option<unknown>): Option.Option<Cause.Cause<E>> =>
match(self, {
onEmpty: Option.some<Cause.Cause<E>>(empty),
onFail: (error) => Option.some(fail(error)),
onDie: (defect) => {
const option = pf(defect)
return Option.isSome(option) ? Option.none() : Option.some(die(defect))
},
onInterrupt: (fiberId) => Option.some(interrupt(fiberId)),
onSequential: Option.mergeWith(sequential),
onParallel: Option.mergeWith(parallel)
})
)

// -----------------------------------------------------------------------------
// Mapping
Expand Down
8 changes: 8 additions & 0 deletions packages/effect/test/Option.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -545,4 +545,12 @@ describe("Option", () => {
assertNone(Option.none().pipe(Option.asVoid))
assertSome(Option.some(1).pipe(Option.asVoid), undefined)
})

it("[internal] mergeWith", () => {
const mergeWith = Option.mergeWith(N.sum)
assertNone(mergeWith(Option.none(), Option.none()))
assertSome(mergeWith(Option.some(1), Option.none()), 1)
assertSome(mergeWith(Option.none(), Option.some(2)), 2)
assertSome(mergeWith(Option.some(1), Option.some(2)), 3)
})
})

0 comments on commit aa26d9b

Please sign in to comment.