@dillonkearns/elm-graphql
Version:
<img src="https://cdn.jsdelivr.net/gh/martimatix/logo-graphqelm/logo.svg" alt="dillonearns/elm-graphql logo" width="40%" align="right">
220 lines (181 loc) • 4.83 kB
Flow
// @flow
import { HKT } from './HKT'
import type { Monoid } from './Monoid'
import type { Applicative } from './Applicative'
import type { Semigroup } from './Semigroup'
import type { Monad } from './Monad'
import type { Foldable } from './Foldable'
import type { Alt } from './Alt'
import type { Plus } from './Plus'
import type { Alternative } from './Alternative'
import type { Extend } from './Extend'
import type { Setoid } from './Setoid'
import type { Traversable } from './Traversable'
import type { MonadError } from './MonadError'
import { id } from './Identity'
import { constant } from './Fun'
class IsMaybe {}
export type MaybeV<A> = ?A;
export type Maybe<A> = HKT<IsMaybe, A>;
export function inj<A>(a: MaybeV<A>): Maybe<A> {
return ((a: any): Maybe<A>)
}
export function prj<A>(fa: Maybe<A>): MaybeV<A> {
return ((fa: any): MaybeV<A>)
}
export function isNothing<A>(x: Maybe<A>): boolean {
return x == Nothing
}
export function isJust<A>(x: Maybe<A>): boolean {
return x != Nothing
}
export function empty<A>(): Maybe<A> {
return Nothing
}
export const pempty = empty
export function concat<A>(semigroup: Semigroup<A>): (fx: Maybe<A>, fy: Maybe<A>) => Maybe<A> {
return function concat(fx, fy) {
const x = prj(fx)
const y = prj(fy)
if (x == null) {
return fy
}
if (y == null) {
return fx
}
return of(semigroup.concat(x, y))
}
}
export function getSemigroup<A>(semigroup: Semigroup<A>): Semigroup<Maybe<A>> {
return {
concat: concat(semigroup)
}
}
export function getMonoid<A>(semigroup: Semigroup<A>): Monoid<Maybe<A>> {
return {
empty,
concat: concat(semigroup)
}
}
export function map<A, B>(f: (a: A) => B, fa: Maybe<A>): Maybe<B> {
const a = prj(fa)
return a == null ? Nothing : inj(f(a))
}
export function ap<A, B>(fab: Maybe<(a: A) => B>, fa: Maybe<A>): Maybe<B> {
const ab = prj(fab)
return ab == null ? Nothing : map(ab, fa)
}
export function of<A>(a: A): Maybe<A> {
return inj(a)
}
export function chain<A, B>(f: (a: A) => Maybe<B>, fa: Maybe<A>): Maybe<B> {
return maybe(Nothing, f, fa)
}
export const Nothing: Maybe<any> = inj(null)
export function reduce<A, B>(f: (b: B, a: A) => B, b: B, fa: Maybe<A>): B {
const a = prj(fa)
return a == null ? b : f(b, a)
}
export function alt<A>(fx: Maybe<A>, fy: Maybe<A>): Maybe<A> {
return fx == Nothing ? fy : fx
}
export function extend<A, B>(f: (ea: Maybe<A>) => B, ea: Maybe<A>): Maybe<B> {
return isNothing(ea) ? Nothing : inj(f(ea))
}
export function equals<A>(setoid: Setoid<A>, fx: Maybe<A>, fy: Maybe<A>): boolean {
const x = prj(fx)
const y = prj(fy)
if (x == null || y == null) {
return true
}
if (x != null || y != null) {
return setoid.equals(x, y)
}
return false
}
export function traverse<F, A, B>(applicative: Applicative<F>, f: (a: A) => HKT<F, B>, ta: Maybe<A>): HKT<F, Maybe<B>> {
const a = prj(ta)
if (a == null) {
return applicative.of(Nothing)
}
return applicative.map(of, f(a))
}
export function throwError<A>(e: void): Maybe<A> { // eslint-disable-line no-unused-vars
return Nothing
}
export function catchError<A>(ma: Maybe<A>, handler: (e: void) => Maybe<A>): Maybe<A> {
const a = prj(ma)
return a == null ? handler() : ma
}
export function getSetoid<A>(setoid: Setoid<A>): Setoid<Maybe<A>> {
return {
equals(fx, fy) {
return equals(setoid, fx, fy)
}
}
}
export function maybe<A, B>(b: B, f: (a: A) => B, fa: Maybe<A>): B {
return reduce((_, a) => f(a), b, fa)
}
export function fromMaybe<A>(a: A, fa: Maybe<A>): A {
return maybe(a, id, fa)
}
export function fromJust<A>(fa: Maybe<A>): A {
const a = prj(fa)
if (a == null) {
throw new Error('fromJust returned a Nothing')
}
return a
}
// Maybe monoid returning the leftmost non-Nothing value.
export const first: Monoid<Maybe<any>> = {
empty,
concat: alt
}
export const toNothing = constant(maybe.Nothing)
/*
Do notation (experimental)
Example:
import * as maybe from '../Maybe'
const x: Maybe<number> = maybe.Do.of(3)
.map(n => n * 2)
.chain(n => maybe.of(n - 1))
.value
*/
export class Do<A> {
static of(a: A): Do<A> {
return new Do(of(a))
}
value: Maybe<A>;
constructor(value: Maybe<A>) {
this.value = value
}
map<B>(f: (a: A) => B): Do<B> {
return new Do(map(f, this.value))
}
chain<B>(f: (a: A) => Maybe<B>): Do<B> {
return new Do(chain(f, this.value))
}
}
if (false) { // eslint-disable-line
({
map,
ap,
of,
chain,
reduce,
alt,
pempty,
extend,
traverse,
throwError,
catchError
}: Monad<IsMaybe> &
Foldable<IsMaybe> &
Alt<IsMaybe> &
Plus<IsMaybe> &
Alternative<IsMaybe> &
Extend<IsMaybe> &
Traversable<IsMaybe> &
MonadError<*, IsMaybe>)
}