Skip to content
This repository has been archived by the owner on May 3, 2021. It is now read-only.

Commit

Permalink
feat: major type system rewrite
Browse files Browse the repository at this point in the history
* implement Kinds interface for accumulating type substitution
  schemes
* implement simplified (read: unindexed) type classes using
  generics and type inferrence to handle adts of various lengths
* update all adts to register their kind and to use the new
  type classes (this is mostly removing now unneeded types since
  inferrence works very well)
* start the process of updating the testing assertions
  • Loading branch information
baetheus committed Apr 2, 2021
1 parent 9d45eca commit 32ddaa0
Show file tree
Hide file tree
Showing 69 changed files with 4,075 additions and 7,038 deletions.
Binary file added .affect.ts.swp
Binary file not shown.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
.vscode
.vim-lsp-settings
draft
draft.ts
bundle
263 changes: 164 additions & 99 deletions CHANGELOG.md

Large diffs are not rendered by default.

46 changes: 38 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,51 @@
# hkts ![Deno](https://github.com/nullpub/hkts/workflows/Deno/badge.svg?branch=master)

Higher kinded types for [Deno](https://deno.land). As an avid user of [fp-ts](https://github.com/gcanti/fp-ts) I wanted to have a similarly full featured environment in Deno. Unfortunately, the fp-ts port to Deno is clunky to use with other functional libraries like [@nll/datum](https://github.com/nullpub/datum), [io-ts](https://github.com/gcanti/io-ts), and [monocle-ts](https://github.com/gcanti/monocle-ts). While I could have ported fp-ts directly, I've come to like the exploratory work done by pelotom in the original [hkts](http://github.com/pelotom/hkts). Thus, I've decided to port the functionality of fp-ts, io-ts, and monocle-ts to Deno using the HKT substitution developed by pelotom.

This library is primarily an exercise, but I intend to maintain 100% test coverage. Instead of breaking out the clones of io-ts, monocle-ts, and datum into other Deno modules they will all be landed here. There will be no barrel exports as importing in Deno is much cleaner without them. Contributions are welcome.
Higher kinded types for [Deno](https://deno.land). As an avid user of
[fp-ts](https://github.com/gcanti/fp-ts) I wanted to have a similarly full
featured environment in Deno. Unfortunately, the fp-ts port to Deno is clunky to
use with other functional libraries like
[@nll/datum](https://github.com/nullpub/datum),
[io-ts](https://github.com/gcanti/io-ts), and
[monocle-ts](https://github.com/gcanti/monocle-ts). While I could have ported
fp-ts directly, I've come to like the exploratory work done by pelotom in the
original [hkts](http://github.com/pelotom/hkts). Thus, I've decided to port the
functionality of fp-ts, io-ts, and monocle-ts to Deno using the HKT substitution
developed by pelotom.

This library is primarily an exercise, but I intend to maintain 100% test
coverage. Instead of breaking out the clones of io-ts, monocle-ts, and datum
into other Deno modules they will all be landed here. There will be no barrel
exports as importing in Deno is much cleaner without them. Contributions are
welcome.

## Installation

This library is meant to be used with Deno, thus it follows the [Deno imports](https://deno.land/manual/examples/import_export) syntax.
This library is meant to be used with Deno, thus it follows the
[Deno imports](https://deno.land/manual/examples/import_export) syntax.

## Conventions

This library focuses first on implementing [static-land](https://github.com/fantasyland/static-land) type classes for a given Algebraic Data Type (ie. Either or Option). These type class modules are then exported from the ADT's namespace (eg. `import { Monad } from 'https://deno.land/x/hkts/option.ts'`).
This library focuses first on implementing
[static-land](https://github.com/fantasyland/static-land) type classes for a
given Algebraic Data Type (ie. Either or Option). These type class modules are
then exported from the ADT's namespace (eg.
`import { Monad } from 'https://deno.land/x/hkts/option.ts'`).

With the exception of instance constructors (ie. getShow or getSemigroup) other ADT functions should all be pipeable. For functions that derive from type class modules, like `chain` or `map`, there are helpers in `derivations.ts` that will generate the pipeable versions for you.
With the exception of instance constructors (ie. getShow or getSemigroup) other
ADT functions should all be pipeable. For functions that derive from type class
modules, like `chain` or `map`, there are helpers in `derivations.ts` that will
generate the pipeable versions for you.

For good examples of the above conventions look at the `either.ts` or `option.ts`.
For good examples of the above conventions look at the `either.ts` or
`option.ts`.

# Documentation

For the foreseeable future this library will not focus on documentation. Questions are welcome via [github issues](https://github.com/nullpub/hkts/issues) but I can't guaruntee speedy responses. Once a decent collection of ADTs and other utilities are ported and all the pre-1.0.0 todo items in `TODO.md` are complete I'll shift to documentation. Even then it's likely that I'll auto-generate the raw docs from exported function and statement types and will devote any time to building an example library that doubles as extra tests.
For the foreseeable future this library will not focus on documentation.
Questions are welcome via
[github issues](https://github.com/nullpub/hkts/issues) but I can't guaruntee
speedy responses. Once a decent collection of ADTs and other utilities are
ported and all the pre-1.0.0 todo items in `TODO.md` are complete I'll shift to
documentation. Even then it's likely that I'll auto-generate the raw docs from
exported function and statement types and will devote any time to building an
example library that doubles as extra tests.
19 changes: 10 additions & 9 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
# Initial Push Todos

- port monocle-ts
- need to finish Traversal
- implement tests for other algebraic modules
- need Traversal and ChainRec still
- port hyper-ts to Deno
- revisit middleware structure
- look into implementing MiddlewareStateEither (might require length 5 constructor)

# Version 1.0.0 features

- look at TODO items across codebase
- curry semigroup and anything else that should be curried
- work through adt by adt to add any useful missing modules
- show
- semigroup
- ord
- etc
- stack safe recursion for sequence constructors
- trampoline?
- auto documentation (port docs-ts)
- auto documentation (port docs-ts?)
- just use deno docs
- spend a week on examples and introduction posts
- work with tmueller?
- consider migrating from const arrows to functions
- TESTS!
109 changes: 68 additions & 41 deletions affect.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,81 @@
import type * as TC from "./type_classes.ts";
import type { _0, _1, _2, _3 } from "./types.ts";
import type * as HKT from "./hkt.ts";

import * as E from "./either.ts";
import { createDo } from "./derivations.ts";
import { flow, identity, pipe } from "./fns.ts";
import { createSequenceStruct, createSequenceTuple } from "./sequence.ts";

/***************************************************************************************************
* @section Types
**************************************************************************************************/
/*******************************************************************************
* Types
******************************************************************************/

export type Affect<R, E, A> = (r: R) => Promise<E.Either<E, A>>;

/***************************************************************************************************
* @section Utilites
**************************************************************************************************/
/*******************************************************************************
* Kind Registration
******************************************************************************/

export const aff = async <A>(a: A): Promise<A> => a;
export const URI = "Affect";

export type URI = typeof URI;

export type URIS = HKT.URIS;

declare module "./hkt.ts" {
// deno-lint-ignore no-explicit-any
export interface Kinds<_ extends any[]> {
[URI]: Affect<_[2], _[1], _[0]>;
}
}

/*******************************************************************************
* Utilites
******************************************************************************/

export const make = <A>(a: A): Promise<A> => Promise.resolve(a);

export const then = <A, B>(fab: (a: A) => B) =>
(p: Promise<A>): Promise<B> => p.then(fab);

/***************************************************************************************************
* @section Constructors
**************************************************************************************************/
/*******************************************************************************
* Constructors
******************************************************************************/

export const ask: <R>() => Affect<R, never, R> = () => async (r) => E.right(r);
export const ask = <R, L = never>(): Affect<R, L, R> => flow(E.right, make);

export const askLeft = <L, R = never>(): Affect<L, L, R> => flow(E.left, make);

export const asks = <R, E = never, A = never>(
fra: (r: R) => Promise<A>,
): Affect<R, E, A> => async (r) => fra(r).then(E.right);
): Affect<R, E, A> => flow(fra, then(E.right));

export const asksLeft = <R, E = never, A = never>(
fre: (r: R) => Promise<E>,
): Affect<R, E, A> => async (r) => fre(r).then(E.left);
): Affect<R, E, A> => flow(fre, then(E.left));

export const right = <R = never, E = never, A = never>(
right: A,
): Affect<R, E, A> => async () => E.right(right);
): Affect<R, E, A> => () => make(E.right(right));

export const left = <R = never, E = never, A = never>(
left: E,
): Affect<R, E, A> => async () => E.left(left);
): Affect<R, E, A> => () => make(E.left(left));

/*******************************************************************************
* Modules
******************************************************************************/

/***************************************************************************************************
* @section Modules
**************************************************************************************************/
export const Functor: TC.Functor<URI> = {
map: (fai) => (ta) => flow(ta, then(E.map(fai))),
};

export const Functor: TC.Functor<Affect<_0, _1, _2>, 3> = {
map: (fab) => (ta) => flow(ta, then(E.map(fab))),
export const Bifunctor: TC.Bifunctor<URI> = {
bimap: (fbj, fai) => (ta) => flow(ta, then(E.bimap(fbj, fai))),
mapLeft: (fbj) => (ta) => flow(ta, then(E.mapLeft(fbj))),
};

export const Apply: TC.Apply<Affect<_0, _1, _2>, 3> = {
export const Apply: TC.Apply<URI> = {
ap: (tfab) =>
(ta) =>
async (r) => {
Expand All @@ -65,36 +89,47 @@ export const Apply: TC.Apply<Affect<_0, _1, _2>, 3> = {
map: Functor.map,
};

export const Applicative: TC.Applicative<Affect<_0, _1, _2>, 3> = {
export const Applicative: TC.Applicative<URI> = {
of: right,
ap: Apply.ap,
map: Functor.map,
};

export const Chain: TC.Chain<Affect<_0, _1, _2>, 3> = {
export const Chain: TC.Chain<URI> = {
ap: Apply.ap,
map: Functor.map,
chain: (fatb) =>
chain: (fati) =>
(ta) =>
async (r) => {
const ea = await ta(r);
return E.isLeft(ea) ? ea : fatb(ea.right)(r);
return E.isLeft(ea) ? ea : fati(ea.right)(r);
},
};

export const Monad: TC.Monad<Affect<_0, _1, _2>, 3> = {
export const Monad: TC.Monad<URI> = {
of: Applicative.of,
ap: Apply.ap,
map: Functor.map,
join: Chain.chain(identity),
chain: Chain.chain,
};

/***************************************************************************************************
* @section Pipeables
**************************************************************************************************/
export const MonadThrow: TC.MonadThrow<URI> = {
...Monad,
throwError: left,
};

/*******************************************************************************
* Pipeables
******************************************************************************/

export const { of, ap, map, join, chain } = Monad;
export const { of, ap, map, join, chain, throwError } = MonadThrow;

export const { bimap, mapLeft } = Bifunctor;

export const sequenceTuple = createSequenceTuple(Apply);

export const sequenceStruct = createSequenceStruct(Apply);

export const compose = <E = never, A = never, B = never>(
aeb: Affect<A, E, B>,
Expand All @@ -109,16 +144,8 @@ export const recover = <E, A>(fea: (e: E) => A) =>
<R>(ta: Affect<R, E, A>): Affect<R, E, A> =>
flow(ta, then(E.fold(flow(fea, E.right), E.right)));

/***************************************************************************************************
* @section Sequence
**************************************************************************************************/

export const sequenceTuple = createSequenceTuple(Apply);

export const sequenceStruct = createSequenceStruct(Apply);

/***************************************************************************************************
/*******************************************************************************
* Do
**************************************************************************************************/
******************************************************************************/

export const { Do, bind, bindTo } = createDo(Monad);

0 comments on commit 32ddaa0

Please sign in to comment.