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

Commit

Permalink
add IO monad (#43)
Browse files Browse the repository at this point in the history
* fix var usage

* add IO monad
  • Loading branch information
gcanti committed Nov 21, 2016
1 parent 64a9e7a commit cf707a9
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/Arr.js
Expand Up @@ -97,7 +97,7 @@ export function equals<A>(setoid: Setoid<A>, fx: Arr<A>, fy: Arr<A>): boolean {
if (x.length !== y.length) {
return false
}
for (var i = 0, len = x.length; i < len; i++) {
for (let i = 0, len = x.length; i < len; i++) {
if (!setoid.equals(x[i], y[i])) {
return false
}
Expand Down
76 changes: 76 additions & 0 deletions src/IO.js
@@ -0,0 +1,76 @@
// @flow
import { HKT } from './HKT'
import type { Monad } from './Monad'
import type { Semigroup } from './Semigroup'
import type { Monoid } from './Monoid'
import type { Eff } from './Eff'

class IsIO {}

export type IOV<A> = () => A;

export type IO<A> = HKT<IsIO, A>;

export function inj<A>(a: IOV<A>): IO<A> {
return ((a: any): IO<A>)
}

export function prj<A>(fa: IO<A>): IOV<A> {
return ((fa: any): IOV<A>)
}

export function runIO<A>(eff: IO<A>): A {
return prj(eff)()
}

export function map<A, B>(f: (a: A) => B, fa: IO<A>): IO<B> {
return inj(() => f(runIO(fa)))
}

export function ap<A, B>(fab: IO<(a: A) => B>, fa: IO<A>): IO<B> {
return inj(() => runIO(fab)(runIO(fa)))
}

export function of<A>(a: A): IO<A> {
return inj(() => a)
}

export function chain<A, B>(f: (a: A) => IO<B>, fa: IO<A>): IO<B> {
return inj(() => runIO(f(runIO(fa))))
}

export function concat<A>(semigroup: Semigroup<A>): (fx: IO<A>, fy: IO<A>) => IO<A> {
return function concat(fx, fy) {
return inj(() => semigroup.concat(runIO(fx), runIO(fy)))
}
}

export function getSemigroup<A>(semigroup: Semigroup<A>): Semigroup<IO<A>> {
return {
concat: concat(semigroup)
}
}

export function getMonoid<A>(monoid: Monoid<A>): Monoid<IO<A>> {
return {
empty: () => of(monoid.empty()),
concat: concat(monoid)
}
}

export function fromEff<E, A>(fa: Eff<E, A>): IO<A> {
return ((fa: any): IO<A>)
}

export function toEff<E, A>(fa: IO<A>): Eff<E, A> {
return ((fa: any): Eff<E, A>)
}

if (false) { // eslint-disable-line
({
map,
ap,
of,
chain
}: Monad<IsIO>)
}
44 changes: 44 additions & 0 deletions test/IO.js
@@ -0,0 +1,44 @@
// @flow

declare var describe: Function;
declare var it: Function;

import assert from 'assert'
import {
of,
map,
ap,
chain,
getMonoid,
runIO
} from '../src/IO'
import {
stringMonoid
} from '../src/Monoid'

describe('IO', () => {

it('map', () => {
const aIO = of('a')
assert.strictEqual(runIO(map(s => s.length, aIO)), 1)
})

it('ap', () => {
const aIO = of('a')
const fIO = of(s => s.length)
assert.strictEqual(runIO(ap(fIO, aIO)), 1)
})

it('chain', () => {
const aIO = of('a')
assert.strictEqual(runIO(chain(s => of(s.length), aIO)), 1)
})

it('concat', () => {
const aIO = of('a')
const bIO = of('b')
const { concat } = getMonoid(stringMonoid)
assert.strictEqual(runIO(concat(aIO, bIO)), 'ab')
})

})

0 comments on commit cf707a9

Please sign in to comment.