Skip to content

Commit

Permalink
initial work on build-npm
Browse files Browse the repository at this point in the history
* try a build and test using it from an npm project
* implement failable createTap for tapping left and right
  • Loading branch information
baetheus committed Oct 23, 2023
1 parent 8a16e1f commit b441354
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 97 deletions.
23 changes: 6 additions & 17 deletions applicable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,27 +70,16 @@ export function apply<U extends Kind, V extends Kind>(
) => <I>(
uvfai: $<U, [$<V, [(a: A) => I, B, C], [D], [E]>, J, K], [L], [M]>,
) => $<U, [$<V, [I, B, C], [D], [E]>, J, K], [L], [M]> {
return <
A,
B = never,
C = never,
D = unknown,
E = unknown,
J = never,
K = never,
L = unknown,
M = unknown,
>(uva: $<U, [$<V, [A, B, C], [D], [E]>, J, K], [L], [M]>) =>
<I>(
uvfai: $<U, [$<V, [(a: A) => I, B, C], [D], [E]>, J, K], [L], [M]>,
): $<U, [$<V, [I, B, C], [D], [E]>, J, K], [L], [M]> => {
// deno-lint-ignore no-explicit-any
return ((uva: any) => (uvfai: any) => {
return U.apply(uva)(
U.map(
(vfai: $<V, [(a: A) => I, B, C], [D], [E]>) =>
(va: $<V, [A, B, C], [D], [E]>) => V.apply(va)(vfai),
// deno-lint-ignore no-explicit-any
(vfai: any) => (va: any) => V.apply(va)(vfai),
)(uvfai),
);
};
// deno-lint-ignore no-explicit-any
}) as any;
}

/**
Expand Down
5 changes: 3 additions & 2 deletions async_either.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import type { Wrappable } from "./wrappable.ts";
import * as E from "./either.ts";
import * as A from "./async.ts";
import * as P from "./promise.ts";
import { createBind, createTap } from "./flatmappable.ts";
import { createTap } from "./failable.ts";
import { createBind } from "./flatmappable.ts";
import { createBindTo } from "./mappable.ts";
import { handleThrow, pipe } from "./fn.ts";
import { resolve } from "./promise.ts";
Expand Down Expand Up @@ -482,7 +483,7 @@ export const WrappableAsyncEither: Wrappable<KindAsyncEither> = {
/**
* @since 2.0.0
*/
export const tap = createTap(FlatmappableAsyncEitherParallel);
export const tap = createTap(FailableAsyncEitherParallel);

/**
* @since 2.0.0
Expand Down
10 changes: 10 additions & 0 deletions decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,16 @@ const traverseArray = A.traverse(FlatmappableDecoded);
*/
export type Decoder<D, A> = FnEither<D, DecodeError, A>;

/**
* @since 2.0.1
*/
export type TypeIn<U> = U extends Decoder<infer D, infer _> ? D : never;

/**
* @since 2.0.1
*/
export type TypeOut<U> = U extends Decoder<infer _, infer A> ? A : never;

/**
* A type that matches any decoder type.
*
Expand Down
5 changes: 3 additions & 2 deletions either.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import type { Traversable } from "./traversable.ts";
import type { Wrappable } from "./wrappable.ts";

import * as O from "./option.ts";
import { createBind, createTap } from "./flatmappable.ts";
import { createTap } from "./failable.ts";
import { createBind } from "./flatmappable.ts";
import { createBindTo } from "./mappable.ts";
import { isNotNil } from "./nil.ts";
import { fromCompare } from "./comparable.ts";
Expand Down Expand Up @@ -506,7 +507,7 @@ export const WrappableEither: Wrappable<KindEither> = { wrap };
/**
* @since 2.0.0
*/
export const tap = createTap(FlatmappableEither);
export const tap = createTap(FailableEither);

/**
* @since 2.0.0
Expand Down
5 changes: 5 additions & 0 deletions examples/failable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { Kind } from "../kind.ts";
import type { Failable } from "../failable.ts";

export function createTryAll<U extends Kind>(F: Failable<U>) {
}
55 changes: 30 additions & 25 deletions examples/tagged_error.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// deno-lint-ignore-file no-explicit-any
import * as RSS from "https://deno.land/x/[email protected]/mod.ts";
import * as TE from "https://raw.githubusercontent.com/baetheus/fun/main/task_either.ts";
import { pipe } from "https://raw.githubusercontent.com/baetheus/fun/main/fns.ts";
import * as AE from "../async_either.ts";
import { pipe } from "../fn.ts";

// ---
// Try implementing a reusable error type
Expand All @@ -16,16 +16,11 @@ export type Err<T extends string, A> = {

export type AnyErr = Err<string, any>;

export const err = <T extends string, A>(type: T) =>
(
error: unknown,
context: A,
): Err<T, A> => ({
tag: "Error",
type,
context,
error,
});
export function err<T extends string, A>(
type: T,
): (error: unknown, context: A) => Err<T, A> {
return (error, context) => ({ tag: "Error", type, context, error });
}

// ---
// Use a little creative typing to extract tag and context pairs and
Expand All @@ -44,9 +39,11 @@ type MapFunc<T, B> = T extends Err<string, infer V>

type ToRecord<T, B> = { [K in ExtractTags<T>]: MapFunc<MatchTag<K, T>, B> };

export const foldErr =
<T extends AnyErr, B>(fns: ToRecord<T, B>) => (ta: T): B =>
(fns[ta.type as keyof ToRecord<T, B>])(ta.error, ta.context);
export function foldErr<T extends AnyErr, B>(
fns: ToRecord<T, B>,
): (ta: T) => B {
return (ta) => (fns[ta.type as keyof ToRecord<T, B>])(ta.error, ta.context);
}

/**
* Wrapping the errors for tryCatch tend to all look like
Expand All @@ -56,7 +53,7 @@ export const foldErr =
export const tagTryCatch = <T extends string, A extends unknown[], O>(
tag: T,
f: (...as: A) => O | PromiseLike<O>,
) => TE.tryCatch(f, err(tag));
) => AE.tryCatch(f, err(tag));

// ---
// Wrap external functions with tagged errors
Expand All @@ -74,24 +71,32 @@ export const stringify = tagTryCatch(
// Get some xml, parse it as rss, and log it
// ---

function logError(annotation: string): <A>(err: unknown, args: A) => void {
return (err, args) => {
console.error(annotation);
console.error({ err, args });
};
}

export const run = pipe(
// Start with a fetch
safeFetch("https://hnrss.org/frontpage-blarg"),
// The default chain widens the left type, picking up the
AE.bindTo("response"),
// The default flatmap widens the left type, picking up the
// additional Err types
TE.chain(getText),
AE.bind("text", ({ response }) => getText(response)),
// Parse the body text
TE.chain(parseFeed),
AE.bind("parsed", ({ text }) => parseFeed(text)),
// Stringify feed values
TE.chain(stringify),
AE.bind("result", ({ parsed }) => stringify(parsed)),
// Output the date
TE.fold(
AE.match(
// Use the taggedError fold to extract all unioned tags
foldErr({
"FetchError": (_error, _args) => console.error("Hello"),
"RssError": console.error,
"TextError": console.error,
"StringifyError": console.error,
"FetchError": logError("Failed during fetch"),
"RssError": logError("Failed during RSS Parsing"),
"TextError": logError("Failed while parsing text body"),
"StringifyError": logError("Failed while stringifying result"),
}),
console.log,
),
Expand Down
35 changes: 33 additions & 2 deletions failable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import type { $, Hold, Kind } from "./kind.ts";
import type { Flatmappable } from "./flatmappable.ts";
import type { NonEmptyArray } from "./array.ts";

import { flow } from "./fn.ts";

/**
* A Failable structure is a Flatmappable that allows for alternative instances,
* failures, and recovery.
Expand Down Expand Up @@ -40,16 +42,45 @@ export interface Failable<U extends Kind> extends Flatmappable<U>, Hold<U> {
* @since 2.0.0
*/
export function createTryAll<U extends Kind>(
{ alt }: Failable<U>,
{ recover }: Failable<U>,
): <A, B, C, D, E>(
...uas: NonEmptyArray<$<U, [A, B, C], [D], [E]>>
) => $<U, [A, B, C], [D], [E]> {
return (...uas) => {
const [head, ...tail] = uas;
let out = head;
for (const ua of tail) {
out = alt(ua)(out);
out = recover(() => ua)(out);
}
return out;
};
}

/**
* Create a tap function for a structure with instances of Wrappable and
* Flatmappable. A tap function allows one to break out of the functional
* codeflow. It is generally not advised to use tap for code flow but to
* consider an escape hatch to do things like tracing or logging.
*
* @since 2.0.0
*/
export function createTap<U extends Kind>(
{ wrap, fail, flatmap, recover }: Failable<U>,
): <A, B>(
onSuccess: (value: A) => void,
onFailure: (value: B) => void,
) => <C = never, D = unknown, E = unknown>(
ua: $<U, [A, B, C], [D], [E]>,
) => $<U, [A, B, C], [D], [E]> {
return (onSuccess, onFailure) =>
flow(
flatmap((a) => {
onSuccess(a);
return wrap(a);
}),
recover((b) => {
onFailure(b);
return fail(b);
}),
);
}
5 changes: 3 additions & 2 deletions fn_either.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import type { Wrappable } from "./wrappable.ts";

import * as E from "./either.ts";
import * as F from "./fn.ts";
import { createBind, createTap } from "./flatmappable.ts";
import { createTap } from "./failable.ts";
import { createBind } from "./flatmappable.ts";
import { createBindTo } from "./mappable.ts";

/**
Expand Down Expand Up @@ -739,7 +740,7 @@ export const WrappableFnEither: Wrappable<KindFnEither> = { wrap };
/**
* @since 2.0.0
*/
export const tap = createTap(FlatmappableFnEither);
export const tap = createTap(FailableFnEither);

/**
* @since 2.0.0
Expand Down
16 changes: 11 additions & 5 deletions optic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,17 @@ export function _unsafeCast<U extends Tag, V extends Tag, S, A>(
* * FoldTag => FlatmappableArray
*/
function getFlatmappable<T extends Tag>(tag: T): Flatmappable<ToKind<T>> {
return (tag === FoldTag
? A.FlatmappableArray
: tag === AffineTag
? O.FlatmappableOption
: I.FlatmappableIdentity) as unknown as Flatmappable<ToKind<T>>;
type Result = Flatmappable<ToKind<T>>;
switch (tag) {
case FoldTag:
return A.FlatmappableArray as unknown as Result;
case AffineTag:
return O.FlatmappableOption as unknown as Result;
case LensTag:
return I.FlatmappableIdentity as unknown as Result;
default:
throw new Error(`Unable to get Flatmappable for ${tag}`);
}
}

/**
Expand Down
Loading

0 comments on commit b441354

Please sign in to comment.