Understanding `O.tap` in Version 3.3.1: Why the Complexity?

Hey all super n00b here first time post so I apologize if this is the wrong place to ask but O.tap has the following code in 3.3.1

export const tap: {
  <A, X>(f: (a: A) => Option<X>): (self: Option<A>) => Option<A>
  <A, X>(self: Option<A>, f: (a: A) => Option<X>): Option<A>
} = dual(2, <A, X>(self: Option<A>, f: (a: A) => Option<X>): Option<A> => flatMap(self, (a) => map(f(a), () => a)))


For the life of me I don't understand why it's not just this.

const tap: {
  <A, X>(f: (a: A) => X): (self: Option<A>) => Option<A>;
  <A, X>(self: Option<A>, f: (a: A) => X): Option<A>;
} = dual(
  2,
  <A, X>(self: Option<A>, f: (a: A) => X): Option<A> =>
    flatMap(self, (a) => {
      f(a);
      return some(a);
    }),
);


Put differently why does O.tap force me to return an Option<X> which it will throw away instead of accepting just anything?
Was this page helpful?