Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Some Pair Transforms #142

Merged
merged 2 commits into from
Aug 28, 2017
Merged
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: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@ All `Crocks` are Constructor functions of the given type, with `Writer` being an
| `IO` | `of` | `ap`, `chain`, `map`, `of`, `run` |
| `List` | `empty`, `fromArray`, `of` | `ap`, `chain`, `concat`, `cons`, `empty`, `equals`, `filter`, `head`, `map`, `of`, `reduce`, `reject`, `sequence`, `tail`, `toArray`, `traverse`, `value` |
| `Maybe` | `Nothing`, `Just`, `of`, `zero` | `alt`, `ap`, `chain`, `coalesce`, `concat`, `equals`, `either`, `map`, `of`, `option`, `sequence`, `traverse`, `zero` |
| `Pair` | --- | `ap`, `bimap`, `chain`, `concat`, `equals`, `extend`, `fst`, `map`, `merge`, `of`, `snd`, `swap` |
| `Pair` | --- | `ap`, `bimap`, `chain`, `concat`, `equals`, `extend`, `fst`, `map`, `merge`, `of`, `snd`, `swap`, `toArray` |
| `Pred` * | `empty` | `concat`, `contramap`, `empty`, `runWith`, `value` |
| `Reader` | `ask`, `of`| `ap`, `chain`, `map`, `of`, `runWith` |
| `Result` | `Err`, `Ok`, `of`| `alt`, `ap`, `bimap`, `chain`, `coalesce`, `concat`, `either`, `equals`, `map`, `of`, `sequence`, `swap`, `traverse` |
| `Star` | -- | `both`, `compose`, `contramap`, `map`, `promap`, `runWith` |
| `State` | `get`, `gets`, `modify` `of`, `put`| `ap`, `chain`, `evalWith`, `execWith`, `map`, `of`, `runWith` |
| `Star` | `id` | `both`, `compose`, `contramap`, `map`, `promap`, `runWith` |
| `State` | `get`, `modify` `of`, `put`| `ap`, `chain`, `evalWith`, `execWith`, `map`, `of`, `runWith` |
| `Unit` | `empty`, `of` | `ap`, `chain`, `concat`, `empty`, `equals`, `map`, `of`, `value` |
| `Writer`| `of` | `ap`, `chain`, `equals`, `log`, `map`, `of`, `read`, `value` |

Expand Down Expand Up @@ -937,3 +937,4 @@ bad
| `resultToFirst` | `Result e a -> First a` | `(a -> Result e b) -> a -> First b` | `crocks/First` |
| `resultToLast` | `Result e a -> Last a` | `(a -> Result e b) -> a -> Last b` | `crocks/Last` |
| `resultToMaybe` | `Result e a -> Maybe a` | `(a -> Result e b) -> a -> Maybe b` | `crocks/Maybe` |
| `writerToPair` | `Writer m a -> Pair m a` | `(a -> Writer m b) -> a -> Pair m b` | `crocks/Pair` |
36 changes: 36 additions & 0 deletions src/Pair/writerToPair.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/** @license ISC License (c) copyright 2017 original and current authors */
/** @author Ian Hofmann-Hicks (evil) */

const Pair = require('../core/Pair')
const curry = require('../core/curry')
const isFunction = require('../core/isFunction')

const isWriter =
x => !!x && isFunction(x.read)

const applyTransform = w =>
Pair(w.log(), w.value())

// writerToPair : Monoid m => Writer m a -> Pair m a
// writerToPair : Monoid m => (a -> Writer m a) -> Pair m b
function writerToPair(writer) {
if(isFunction(writer)) {
return function(x) {
const m = writer(x)

if(!isWriter(m)) {
throw new TypeError('writerToPair: Writer returing function required')
}

return applyTransform(m)
}
}

if(isWriter(writer)) {
return applyTransform(writer)
}

throw new TypeError('writerToPair: Writer or Writer returing function required')
}

module.exports = curry(writerToPair)
84 changes: 84 additions & 0 deletions src/Pair/writerToPair.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
const test = require('tape')
const helpers = require('../../test/helpers')
const Last = require('../../test/LastMonoid')

const bindFunc = helpers.bindFunc

const Pair = require('.')
const Writer = require('../Writer')(Last)

const constant = require('../core/constant')
const identity = require('../core/identity')
const isFunction = require('../core/isFunction')
const isSameType = require('../core/isSameType')

const writerToPair = require('./writerToPair')

test('writerToPair transform', t => {
const f = bindFunc(writerToPair)

t.ok(isFunction(writerToPair), 'is a function')

const err = /writerToPair: Writer or Writer returing function required/
t.throws(f(undefined), err, 'throws if arg is undefined')
t.throws(f(null), err, 'throws if arg is null')
t.throws(f(0), err, 'throws if arg is a falsey number')
t.throws(f(1), err, 'throws if arg is a truthy number')
t.throws(f(''), err, 'throws if arg is a falsey string')
t.throws(f('string'), err, 'throws if arg is a truthy string')
t.throws(f(false), err, 'throws if arg is false')
t.throws(f(true), err, 'throws if arg is true')
t.throws(f([]), err, 'throws if arg is an array')
t.throws(f({}), err, 'throws if arg is an object')

t.end()
})

test('writerToPair with Writer', t => {
const value = 'something'
const log = 'log'

const p = writerToPair(Writer(log, value))

t.ok(isSameType(Pair, p), 'returns a Pair')

t.equals(p.snd(), value, 'second contains the value')
t.ok(isSameType(Last, p.fst()), 'first contains the Writers Monoid')
t.equals(p.fst().value(), log, 'first Monoid wraps the same log value from Writer')

t.end()
})

test('writerToPair with Writer returning function', t => {
const value = 'something'
const log = 'log'

t.ok(isFunction(constant(writerToPair(Writer(log, value)))), 'returns a function')

const f = bindFunc(writerToPair(identity))

const err = /writerToPair: Writer returing function required/
t.throws(f(undefined), err, 'throws if function returns undefined')
t.throws(f(null), err, 'throws if function returns null')
t.throws(f(0), err, 'throws if function returns a falsey number')
t.throws(f(1), err, 'throws if function returns a truthy number')
t.throws(f(''), err, 'throws if function returns a falsey string')
t.throws(f('string'), err, 'throws if function returns a truthy string')
t.throws(f(false), err, 'throws if function returns false')
t.throws(f(true), err, 'throws if function returns true')
t.throws(f([]), err, 'throws if function returns an array')
t.throws(f({}), err, 'throws if function returns an object')

const lift =
x => Writer(log, x)

const p = writerToPair(lift, value)

t.ok(isSameType(Pair, p), 'returns a Pair')

t.equals(p.snd(), value, 'second contains the value')
t.ok(isSameType(Last, p.fst()), 'first contains the Writers Monoid')
t.equals(p.fst().value(), log, 'first Monoid wraps the same log value from Writer')

t.end()
})
10 changes: 7 additions & 3 deletions src/core/Pair.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ function Pair(l, r) {
const inspect =
() => `Pair(${_inspect(l)},${_inspect(r)} )`

const toArray =
() => [ l, r ]

function merge(fn) {
if(!isFunction(fn)) {
throw new TypeError('Pair.merge: Binary function required')
Expand Down Expand Up @@ -144,9 +147,10 @@ function Pair(l, r) {
}

return {
inspect, fst, snd, type,
merge, equals, concat, swap,
map, bimap, ap, chain, extend
inspect, fst, snd, toArray,
type, merge, equals, concat,
swap, map, bimap, ap, chain,
extend
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/core/Pair.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ test('Pair snd', t => {
t.end()
})

test('Pair toArray', t => {
const p = Pair(34, 'string')

t.ok(isFunction(p.toArray), 'provides a toArray function')
t.same(p.toArray(), [ 34, 'string' ], 'returns an array with the Pairs values')

t.end()
})

test('Pair merge', t => {
const p = Pair(1, 20)

Expand Down
3 changes: 2 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ const transforms = {
resultToEither: require('./Either/resultToEither'),
resultToFirst: require('./First/resultToFirst'),
resultToLast: require('./Last/resultToLast'),
resultToMaybe: require('./Maybe/resultToMaybe')
resultToMaybe: require('./Maybe/resultToMaybe'),
writerToPair: require('./Pair/writerToPair')
}

module.exports = Object.assign(
Expand Down
2 changes: 2 additions & 0 deletions src/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ const resultToEither = require('./Either/resultToEither')
const resultToFirst = require('./First/resultToFirst')
const resultToLast = require('./Last/resultToLast')
const resultToMaybe = require('./Maybe/resultToMaybe')
const writerToPair = require('./Pair/writerToPair')

test('entry', t => {
t.equal(crocks.toString(), '[object Object]', 'is an object')
Expand Down Expand Up @@ -381,6 +382,7 @@ test('entry', t => {
t.equal(crocks.resultToFirst, resultToFirst, 'provides the resultToFirst transform')
t.equal(crocks.resultToLast, resultToLast, 'provides the resultToLast transform')
t.equal(crocks.resultToMaybe, resultToMaybe, 'provides the resultToMaybe transform')
t.equal(crocks.writerToPair, writerToPair, 'provides the writerToPair transform')

t.end()
})