Skip to content
This repository has been archived by the owner on Sep 9, 2023. It is now read-only.

Docs and tests updates #4

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "phantasy",
"version": "0.10.4",
"version": "0.10.5",
"description": "",
"author": "Tim Kuminecz <tkuminecz@gmail.com>",
"license": "MIT",
Expand Down Expand Up @@ -54,10 +54,9 @@
"npm-run-all": "^3.1.2",
"nyc": "^10.0.0",
"tap-diff": "^0.1.1",
"tape": "^4.6.2"
"tape": "4.5.1"
},
"dependencies": {
"bluebird": "^3.4.6",
"tape": "4.5.1"
"bluebird": "^3.4.6"
}
}
4 changes: 3 additions & 1 deletion src/eff.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { Task } from './task';
/**
* The `Eff` monad
*
* Represents synchronous computations which are both dependency-injected and explicitly effectful
* Represents synchronous computations which are both dependency-injected and
* explicitly effectful. `Eff` can be used for effectful code where the effect
* resolvers are injected. This allows the effect handling to be customizable.
*/
export class Eff<E: {}, A> {

Expand Down
41 changes: 28 additions & 13 deletions src/identity.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,80 @@
import { inspect } from 'util';

/**
* The Identity monad
* The `Identity` monad
*
* Simply acts a container for values without any additional behavior
*
* @example let a = Identity.of(42)
*/
export class Identity<A> {

data: A

/**
* Constructs a new Maybe instance
*
* @private
*/
constructor(data: A): void {
this.data = data;
}

/**
* map :: Identity a ~> (a -> b) -> Identity b
* `map :: Identity a ~> (a -> b) -> Identity b`
*
* Transforms the value in the `Identity` instance
*/
map<B>(f: (a: A) => B): Identity<B> {
return Identity.of(f(this.data));
map<B>(transform: (a: A) => B): Identity<B> {
return Identity.of(transform(this.data));
}

/**
* andThen :: Identity a ~> (a -> Identity b) -> Identity b
* `andThen :: Identity a ~> (a -> Identity b) -> Identity b`
*
* Chains the value of the `Identity` instance
* with another `Identity`-producing function
*/
andThen<B>(next: (a: A) => Identity<B>): Identity<B> {
return next(this.data);
}

/**
* toString :: Identity a ~> () -> String
* `toString :: Identity a ~> () -> String`
*
* Returns a string representation of the `Identity` instance
*/
toString(): string {
return `Identity ${ inspect(this.data) }`;
}

/**
* of :: a -> Identity a
* `of :: a -> Identity a`
*
* Returns an `Identity` instance wrapping the giving value
*/
static of(a: A): Identity<A> {
return new Identity(a);
}

/**
* lift :: (a -> b) -> Identity a -> Identity b
* `lift :: (a -> b) -> Identity a -> Identity b`
*/
static lift<A, B>(f: (a: A) => B): * {
static lift<A, B>(f: (a: A) => B): (a: Identity<A>) => Identity<B> {
return (ma) => ma.andThen(a => Identity.of(f(a)));
}

/**
* lift2 :: (a -> b -> c) -> Identity a -> Identity b -> Identity c
* `lift2 :: (a -> b -> c) -> (Identity a -> Identity b) -> Identity c`
*/
static lift2<A, B, C>(f: (a: A, b: B) => C): * {
static lift2<A, B, C>(f: (a: A, b: B) => C): (a: Identity<A>, b: Identity<B>) => Identity<C> {
return (ma, mb) => ma.andThen(a => mb.andThen(b => Identity.of(f(a, b))));
}

/**
* lift3 :: (a -> b -> c -> d) -> Identity a -> Identity b -> Identity c -> Identity d
* `lift3 :: (a -> b -> c -> d) -> (Identity a -> Identity b -> Identity c) -> Identity d`
*/
static lift3<A, B, C, D>(f: (a: A, b: B, c: C) => D): * {
static lift3<A, B, C, D>(f: (a: A, b: B, c: C) => D): (a: Identity<A>, b: Identity<B>, c: Identity<C>) => Identity<D> {
return (ma: Identity<A>, mb: Identity<B>, mc: Identity<C>) => ma.andThen(a => mb.andThen(b => mc.andThen(c => Identity.of(f(a, b, c)))));
}

Expand Down
50 changes: 41 additions & 9 deletions src/io.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,75 @@
/**
* The `IO` monad
*
* Represents a potentially-effectful synchronous computation
* Represents a potentially-effectful synchronous computation.
*/
export class IO<A> {

runIO: () => A
_runIO: () => A

/**
* Constructs a new IO instance
* Constructs a new IO instance.
*
* @private
*/
constructor(runIO: () => A): void {
this.runIO = runIO;
this._runIO = runIO;
}

/**
* `runIO :: IO a ~> () -> a`
*
* Executes the function contained in the `IO` instance and returns the produced value. Note that any side-effects in the `IO` would be performed at this time.
*
* @example let a = IO.of(42);
*
* a.runIO() === 42;
*/
runIO(): A {
return this._runIO();
}

/**
* `map :: IO a ~> (a -> b) -> IO b`
*
* Transforms the result of the `IO` instance
* Transforms the result of the `IO` instance.
*
* @example let a = IO.of(2);
*
* a.map(a => a * 2) === IO.of(4);
*/
map<B>(transform: (a: A) => B): IO<B> {
return IO.of(transform(this.runIO()));
map<B>(f: (a: A) => B): IO<B> {
return IO.of(f(this.runIO()));
}

/**
* `andThen :: IO a ~> (a -> IO b) -> IO b`
*
* Chains the result of the `IO` instance with another `IO`-producing function
* Chains the result of the `IO` instance with another `IO`-producing function.
*
* @example let a = IO.of(42);
*
* a.andThen(a => IO.of(a / 2)) == IO.of(24);
*/
andThen<B>(next: (a: A) => IO<B>): IO<B> {
return next(this.runIO());
}

/**
* `from :: (() -> a) -> IO a`
*
* Returns a `IO` instance wrapping the given function.
*/
static from<A>(f: () => A): IO<A> {
return new IO(f);
}

/**
* `of :: a -> IO a`
*
* Returns an `IO` instance that always produces the given value
* Returns an `IO` instance that always produces the given value.
*
* @example let a = IO.of(42);
*/
static of(value: A): IO<A> {
return new IO(() => value);
Expand Down
40 changes: 25 additions & 15 deletions src/maybe.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,19 @@ type MaybeData<A> = Just<A> | Nothing
/**
* The `Maybe` monad
*
* Represents the possibility of a value or nothing. Commonly used
* to safely deal with nullable values because it is composable and
* forces the developer to explicitly handle the null case.
* Represents the possibility of the presence or absence of a value.
* Commonly used to safely deal with nullable values because it is
* composable and forces the developer to explicitly handle the null case.
*
* @example // construct a Maybe with a value
* let some = Maybe.Just(42);
*
* // construct a maybe absent of a value
* let none = Maybe.Nothing;
*
* // create Maybes from nullable values
* let ma = Maybe.of('foo'),
* mb = Maybe.of(null);
*/
export class Maybe<A> {

Expand Down Expand Up @@ -65,7 +75,7 @@ export class Maybe<A> {
/**
* `isJust :: Maybe a ~> () -> Bool`
*
* Returns `true` if the instance contains a value
* Returns `true` if the `Maybe` instance contains a value
*/
isJust(): bool {
return this.cases({
Expand All @@ -77,7 +87,7 @@ export class Maybe<A> {
/**
* `isNothing :: Maybe a ~> () -> Bool`
*
* Returns `true` if the instance is absent of value
* Returns `true` if the `Maybe` instance is absent of value
*/
isNothing(): bool {
return !this.isJust();
Expand All @@ -102,9 +112,9 @@ export class Maybe<A> {
* If `Just`, returns `Just` the value transformed by
* the given function, otherwise returns `Nothing`
*/
map<B>(transform: (a: A) => B): Maybe<B> {
map<B>(f: (a: A) => B): Maybe<B> {
return (this.data instanceof Just)
? Maybe.Just(transform(this.data.value))
? Maybe.Just(f(this.data.value))
: Maybe.Nothing;
}

Expand Down Expand Up @@ -135,7 +145,7 @@ export class Maybe<A> {
/**
* `of :: a -> Maybe a`
*
* Takes a nullable value and constructs a new `Maybe` instance containing it
* Returns `Maybe.Just` of the given value if it is not null and `Maybe.Nothing` otherwise
*/
static of(a: ?A): Maybe<A> {
return (a == null)
Expand All @@ -146,7 +156,7 @@ export class Maybe<A> {
/**
* `Just :: a -> Maybe a`
*
* Data constructor for indicating the presence of a value
* Returns a a `Maybe` instance containing the given value
*/
static Just<A>(a: A): Maybe<A> {
return new Maybe(new Just(a));
Expand All @@ -155,7 +165,7 @@ export class Maybe<A> {
/**
* `Nothing :: Maybe a`
*
* Data constructor for indicating the absence of a value
* A `Maybe` instance which is absent of a value
*/
static Nothing = (new Maybe(new Nothing()): any);

Expand All @@ -180,25 +190,25 @@ export class Maybe<A> {
*
* Takes an unary function and returns an equivalent unary function which operates on `Maybe` values
*/
static lift<A, B>(f: (a: A) => B): * {
static lift<A, B>(f: (a: A) => B): (a: Maybe<A>) => Maybe<B> {
return (ma) => ma.andThen(a => Maybe.of(f(a)));
}

/**
* `lift2 :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c`
* `lift2 :: (a -> b -> c) -> (Maybe a -> Maybe b) -> Maybe c`
*
* Takes an binary function and returns an equivalent binary function which operates on `Maybe` values
*/
static lift2<A, B, C>(f: (a: A, b: B) => C): * {
static lift2<A, B, C>(f: (a: A, b: B) => C): (a: Maybe<A>, b: Maybe<B>) => Maybe<C> {
return (ma, mb) => ma.andThen(a => mb.andThen(b => Maybe.of(f(a, b))));
}

/**
* `lift3 :: (a -> b -> c -> d) -> Maybe a -> Maybe b -> Maybe c -> Maybe d`
* `lift3 :: (a -> b -> c -> d) -> (Maybe a -> Maybe b -> Maybe c) -> Maybe d`
*
* Takes an ternary function and returns an equivalent ternary function which operates on `Maybe` values
*/
static lift3<A, B, C, D>(f: (a: A, b: B, c: C) => D): * {
static lift3<A, B, C, D>(f: (a: A, b: B, c: C) => D): (a: Maybe<A>, b: Maybe<B>, c: Maybe<C>) => Maybe<D> {
return (ma, mb, mc) => ma.andThen(a => mb.andThen(b => mc.andThen(c => Maybe.of(f(a, b, c)))));
}

Expand Down
Loading