import { Mapper, SideEffect } from "../fn/mod.ts"; export interface ITrace { addTrace: Mapper>; trace: SideEffect; } export type ITraceableTuple = [T, Trace]; export type ITraceableMapper> = ( w: W, ) => U; export interface ITraceable { readonly item: T; readonly trace: ITrace; move(u: U): ITraceable; map: ( mapper: ITraceableMapper, ) => ITraceable; bimap: ( mapper: ITraceableMapper>, ) => ITraceable; peek: (peek: ITraceableMapper) => ITraceable; flatMap: ( mapper: ITraceableMapper>, ) => ITraceable; flatMapAsync( mapper: ITraceableMapper>>, ): ITraceable, Trace>; } export class TraceableImpl implements ITraceable { protected constructor( readonly item: T, readonly trace: ITrace, ) {} public map(mapper: ITraceableMapper) { const result = mapper(this); return new TraceableImpl(result, this.trace); } public flatMap( mapper: ITraceableMapper>, ): ITraceable { return mapper(this); } public flatMapAsync( mapper: ITraceableMapper>>, ): ITraceable, L> { return new TraceableImpl( mapper(this).then(({ item }) => item), this.trace, ); } public peek(peek: ITraceableMapper) { peek(this); return this; } public move(t: Tt): ITraceable { return this.map(() => t); } public bimap(mapper: ITraceableMapper>) { const [item, trace] = mapper(this); return new TraceableImpl(item, this.trace.addTrace(trace)); } }