-
Notifications
You must be signed in to change notification settings - Fork 102
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
1,144 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/** @license ISC License (c) copyright 2017 original and current authors */ | ||
/** @author Ian Hofmann-Hicks (evil) */ | ||
|
||
const _implements = require('../internal/implements') | ||
const _inspect = require('../internal/inspect') | ||
|
||
const constant = require('../combinators/constant') | ||
const identity = require('../combinators/identity') | ||
const isSameType = require('../predicates/isSameType') | ||
|
||
const Maybe = require('../crocks/Maybe') | ||
|
||
const _empty = | ||
() => Last(Maybe.Nothing()) | ||
|
||
const _type = | ||
constant('Last') | ||
|
||
function Last(x) { | ||
if(!arguments.length) { | ||
throw new TypeError('Last: Requires one argument') | ||
} | ||
|
||
const maybe = | ||
!isSameType(Maybe, x) ? Maybe.of(x) : x.map(identity) | ||
|
||
const value = | ||
constant(maybe) | ||
|
||
const type = | ||
_type | ||
|
||
const empty = | ||
_empty | ||
|
||
const inspect = | ||
constant(`Last(${_inspect(maybe)} )`) | ||
|
||
const option = | ||
maybe.option | ||
|
||
function concat(m) { | ||
if(!isSameType(Last, m)) { | ||
throw new TypeError('Last.concat: Last required') | ||
} | ||
|
||
const n = | ||
m.value().map(identity) | ||
|
||
return Last( | ||
maybe.either( | ||
constant(n), | ||
constant(n.either(constant(maybe), constant(n))) | ||
) | ||
) | ||
} | ||
|
||
return { | ||
concat, empty, inspect, option, type, value | ||
} | ||
} | ||
|
||
Last['@@implements'] = _implements( | ||
[ 'concat', 'empty' ] | ||
) | ||
|
||
Last.empty = | ||
_empty | ||
|
||
Last.type = | ||
_type | ||
|
||
module.exports = Last |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
const test = require('tape') | ||
const helpers = require('../test/helpers') | ||
|
||
const bindFunc = helpers.bindFunc | ||
|
||
const isFunction = require('../predicates/isFunction') | ||
const isObject = require('../predicates/isObject') | ||
const isSameType = require('../predicates/isSameType') | ||
|
||
const constant = require('../combinators/constant') | ||
|
||
const Maybe = require('../crocks/Maybe') | ||
const Last = require('./Last') | ||
|
||
const extract = m => m.option('empty') | ||
|
||
test('Last', t => { | ||
t.ok(isFunction(Last), 'is a function') | ||
t.ok(isObject(Last(0)), 'returns an object') | ||
|
||
t.ok(isFunction(Last.empty), 'provides an empty function') | ||
t.ok(isFunction(Last.type), 'provides a type function') | ||
|
||
const err = /Last: Requires one argument/ | ||
t.throws(Last, err, 'throws when passed nothing') | ||
|
||
t.end() | ||
}) | ||
|
||
test('Last @@implements', t => { | ||
const f = Last['@@implements'] | ||
|
||
t.equal(f('concat'), true, 'implements concat func') | ||
t.equal(f('empty'), true, 'implements empty func') | ||
|
||
t.end() | ||
}) | ||
|
||
test('Last inspect', t => { | ||
const val = Last(0) | ||
const just = Last(Maybe.Just(1)) | ||
const nothing = Last(Maybe.Nothing()) | ||
|
||
t.ok(isFunction(val.inspect), 'provides an inspect function') | ||
t.equal(val.inspect(), 'Last( Just 0 )', 'returns inspect string for value construction') | ||
t.equal(just.inspect(), 'Last( Just 1 )', 'returns inspect string for value construction') | ||
t.equal(nothing.inspect(), 'Last( Nothing )', 'returns inspect string for value construction') | ||
|
||
t.end() | ||
}) | ||
|
||
test('Last value', t => { | ||
t.ok(isFunction(Last(0).value), 'is a function') | ||
|
||
const val = Last(1).value() | ||
const just = Last(Maybe.Just(2)).value() | ||
const nothing = Last(Maybe.Nothing()).value() | ||
|
||
t.ok(isSameType(Maybe, val), 'returns a Maybe when constructed with a value') | ||
t.ok(isSameType(Maybe, just), 'returns a Maybe when constructed with a Just') | ||
t.ok(isSameType(Maybe, nothing), 'returns a Maybe when constructed with a nothing') | ||
|
||
t.equal(extract(val), 1, 'returns a Just when constructed with a value') | ||
t.equal(extract(just), 2, 'returns a Just when constructed with a Just') | ||
t.equal(extract(nothing), 'empty', 'returns a Nothing when constructed with a Nothing') | ||
|
||
t.end() | ||
}) | ||
|
||
test('Last type', t => { | ||
t.ok(isFunction(Last(0).type), 'is a function') | ||
t.equal(Last.type, Last(0).type, 'is the same function as the static type') | ||
t.equal(Last(0).type(), 'Last', 'reports Last') | ||
|
||
t.end() | ||
}) | ||
|
||
test('Last option', t => { | ||
const val = Last('val') | ||
const just = Last('just') | ||
const nothing = Last('nothing') | ||
|
||
t.equal(val.option('nothing'), 'val', 'extracts the underlying Just value') | ||
t.equal(just.option('nothing'), 'just', 'extracts the underlying Just value') | ||
t.equal(nothing.option('nothing'), 'nothing', 'returns the provided value with underlying Nothing') | ||
|
||
t.end() | ||
}) | ||
|
||
test('Last concat functionality', t => { | ||
const a = Last('a') | ||
const b = Last('b') | ||
|
||
const notLast = { type: constant('Last...Not') } | ||
|
||
const cat = bindFunc(a.concat) | ||
|
||
const err = /Last.concat: Last required/ | ||
t.throws(cat(undefined), err, 'throws with undefined') | ||
t.throws(cat(null), err, 'throws with null') | ||
t.throws(cat(0), err, 'throws with falsey number') | ||
t.throws(cat(1), err, 'throws with truthy number') | ||
t.throws(cat(''), err, 'throws with falsey string') | ||
t.throws(cat('string'), err, 'throws with truthy string') | ||
t.throws(cat(false), err, 'throws with false') | ||
t.throws(cat(true), err, 'throws with true') | ||
t.throws(cat([]), err, 'throws with an array') | ||
t.throws(cat({}), err, 'throws with an object') | ||
t.throws(cat(notLast), err, 'throws when passed non-Last') | ||
|
||
t.equal(extract(a.concat(b)), 'b', 'returns the last value concatted') | ||
|
||
t.end() | ||
}) | ||
|
||
test('Last concat properties (Semigroup)', t => { | ||
const a = Last(0) | ||
const b = Last(1) | ||
const c = Last('') | ||
|
||
const left = a.concat(b).concat(c) | ||
const right = a.concat(b.concat(c)) | ||
|
||
t.ok(isFunction(a.concat), 'provides a concat function') | ||
t.equal(extract(left), extract(right), 'associativity') | ||
t.equal(a.concat(b).type(), a.type(), 'returns an Last') | ||
|
||
t.end() | ||
}) | ||
|
||
test('Last empty functionality', t => { | ||
const x = Last.empty() | ||
|
||
t.equal(x.type(), 'Last', 'provides an Last') | ||
t.equal(extract(x), 'empty', 'provides a true value') | ||
|
||
t.end() | ||
}) | ||
|
||
test('Last empty properties (Monoid)', t => { | ||
const m = Last(3) | ||
|
||
t.ok(isFunction(m.concat), 'provides a concat function') | ||
t.ok(isFunction(m.empty), 'provides an empty function') | ||
|
||
const right = m.concat(m.empty()) | ||
const left = m.empty().concat(m) | ||
|
||
t.equal(extract(right), extract(m), 'right identity') | ||
t.equal(extract(left), extract(m), 'left identity') | ||
|
||
t.end() | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/** @license ISC License (c) copyright 2017 original and current authors */ | ||
/** @author Ian Hofmann-Hicks (evil) */ | ||
|
||
const curry = require('../helpers/curry') | ||
|
||
const isFunction = require('../predicates/isFunction') | ||
const isSameType = require('../predicates/isSameType') | ||
|
||
const Either = require('../crocks/Either') | ||
const Last = require('../monoids/Last') | ||
|
||
const applyTransform = either => | ||
either.either(Last.empty, Last) | ||
|
||
// eitherToLast : Either b a -> Last a | ||
// eitherToLast : (a -> Either c b) -> a -> Last b | ||
function eitherToLast(either) { | ||
if(isFunction(either)) { | ||
return function(x) { | ||
const m = either(x) | ||
|
||
if(!isSameType(Either, m)) { | ||
throw new TypeError('eitherToLast: Either returing function required') | ||
} | ||
|
||
return applyTransform(m) | ||
} | ||
} | ||
|
||
if(isSameType(Either, either)) { | ||
return applyTransform(either) | ||
} | ||
|
||
throw new TypeError('eitherToLast: Either or Either returing function required') | ||
} | ||
|
||
module.exports = curry(eitherToLast) |
Oops, something went wrong.