Skip to content

Commit c6dcdf2

Browse files
evilsoftIan Hofmann-Hicks
authored and
Ian Hofmann-Hicks
committed
move Star and Arrow from Semigroups to Semigroupoids
1 parent af7e578 commit c6dcdf2

20 files changed

+448
-70
lines changed

README.md

+87-15
Large diffs are not rendered by default.

crocks.js

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const helpers = {
3838
compose: require('./helpers/compose'),
3939
composeK: require('./helpers/composeK'),
4040
composeP: require('./helpers/composeP'),
41+
composeS: require('./helpers/composeS'),
4142
curry: require('./helpers/curry'),
4243
defaultProps: require('./helpers/defaultProps'),
4344
defaultTo: require('./helpers/defaultTo'),
@@ -59,6 +60,7 @@ const helpers = {
5960
pipe: require('./helpers/pipe'),
6061
pipeK: require('./helpers/pipeK'),
6162
pipeP: require('./helpers/pipeP'),
63+
pipeS: require('./helpers/pipeS'),
6264
prop: require('./helpers/prop'),
6365
propPath: require('./helpers/propPath'),
6466
safe: require('./helpers/safe'),
@@ -134,6 +136,7 @@ const predicates = {
134136
isApply: require('./predicates/isApply'),
135137
isArray: require('./predicates/isArray'),
136138
isBoolean: require('./predicates/isBoolean'),
139+
isCategory: require('./predicates/isCategory'),
137140
isChain: require('./predicates/isChain'),
138141
isDefined: require('./predicates/isDefined'),
139142
isEmpty: require('./predicates/isEmpty'),
@@ -150,6 +153,7 @@ const predicates = {
150153
isSameType: require('./predicates/isSameType'),
151154
isSetoid: require('./predicates/isSetoid'),
152155
isSemigroup: require('./predicates/isSemigroup'),
156+
isSemigroupoid: require('./predicates/isSemigroupoid'),
153157
isString: require('./predicates/isString'),
154158
isTraversable: require('./predicates/isTraversable')
155159
}

crocks.spec.js

+8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const branch = require('./helpers/branch')
1717
const compose = require('./helpers/compose')
1818
const composeK = require('./helpers/composeK')
1919
const composeP = require('./helpers/composeP')
20+
const composeS = require('./helpers/composeS')
2021
const curry = require('./helpers/curry')
2122
const defaultProps = require('./helpers/defaultProps')
2223
const defaultTo = require('./helpers/defaultTo')
@@ -38,6 +39,7 @@ const pick = require('./helpers/pick')
3839
const pipe = require('./helpers/pipe')
3940
const pipeK = require('./helpers/pipeK')
4041
const pipeP = require('./helpers/pipeP')
42+
const pipeS = require('./helpers/pipeS')
4143
const prop = require('./helpers/prop')
4244
const propPath = require('./helpers/propPath')
4345
const safe = require('./helpers/safe')
@@ -123,6 +125,7 @@ const isApplicative = require('./predicates/isApplicative')
123125
const isApply = require('./predicates/isApply')
124126
const isArray = require('./predicates/isArray')
125127
const isBoolean = require('./predicates/isBoolean')
128+
const isCategory = require('./predicates/isCategory')
126129
const isChain = require('./predicates/isChain')
127130
const isDefined = require('./predicates/isDefined')
128131
const isEmpty = require('./predicates/isEmpty')
@@ -138,6 +141,7 @@ const isObject = require('./predicates/isObject')
138141
const isPromise = require('./predicates/isPromise')
139142
const isSameType = require('./predicates/isSameType')
140143
const isSemigroup = require('./predicates/isSemigroup')
144+
const isSemigroupoid = require('./predicates/isSemigroupoid')
141145
const isSetoid = require('./predicates/isSetoid')
142146
const isString = require('./predicates/isString')
143147
const isTraversable = require('./predicates/isTraversable')
@@ -172,6 +176,7 @@ test('entry', t => {
172176
t.equal(crocks.compose, compose, 'provides the compose function')
173177
t.equal(crocks.composeK, composeK, 'provides the composeK function')
174178
t.equal(crocks.composeP, composeP, 'provides the composeP function')
179+
t.equal(crocks.composeS, composeS, 'provides the composeS function')
175180
t.equal(crocks.curry, curry, 'provides the curry function')
176181
t.equal(crocks.defaultProps, defaultProps, 'provides the defaultProps function')
177182
t.equal(crocks.defaultTo, defaultTo, 'provides the defaultTo function')
@@ -193,6 +198,7 @@ test('entry', t => {
193198
t.equal(crocks.pipe, pipe, 'provides the pipe function')
194199
t.equal(crocks.pipeK, pipeK, 'provides the pipeK function')
195200
t.equal(crocks.pipeP, pipeP, 'provides the pipeP function')
201+
t.equal(crocks.pipeS, pipeS, 'provides the pipeS function')
196202
t.equal(crocks.prop, prop, 'provides the prop function')
197203
t.equal(crocks.propPath, propPath, 'provides the propPath function')
198204
t.equal(crocks.safe, safe, 'provides the safe function')
@@ -278,6 +284,7 @@ test('entry', t => {
278284
t.equal(crocks.isApply, isApply, 'provides the isApply function')
279285
t.equal(crocks.isArray, isArray, 'provides the isArray function')
280286
t.equal(crocks.isBoolean, isBoolean, 'provides the isBoolean function')
287+
t.equal(crocks.isCategory, isCategory, 'provides the isCategory function')
281288
t.equal(crocks.isChain, isChain, 'provides the isChain function')
282289
t.equal(crocks.isDefined, isDefined, 'provides the isDefined function')
283290
t.equal(crocks.isEmpty, isEmpty, 'provides the isEmpty function')
@@ -293,6 +300,7 @@ test('entry', t => {
293300
t.equal(crocks.isPromise, isPromise, 'provides the isPromise function')
294301
t.equal(crocks.isSameType, isSameType, 'provides the isSameType function')
295302
t.equal(crocks.isSemigroup, isSemigroup, 'provides the isSemigroup function')
303+
t.equal(crocks.isSemigroupoid, isSemigroupoid, 'provides the isSemigroupoid function')
296304
t.equal(crocks.isSetoid, isSetoid, 'provides the isSetoid function')
297305
t.equal(crocks.isString, isString, 'provides the isString function')
298306
t.equal(crocks.isTraversable, isTraversable, 'provides the isTraversable function')

crocks/Arrow.js

+15-18
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
/** @license ISC License (c) copyright 2016 original and current authors */
22
/** @author Ian Hofmann-Hicks (evil) */
33

4-
const isFunction = require('../predicates/isFunction')
5-
6-
const isSameType = require('../predicates/isSameType')
74
const _inspect = require('../internal/inspect')
8-
9-
const compose = require('../helpers/compose')
10-
11-
const identity = require('../combinators/identity')
5+
const composeB = require('../combinators/composeB')
126
const constant = require('../combinators/constant')
7+
const identity = require('../combinators/identity')
8+
const isFunction = require('../predicates/isFunction')
9+
const isSameType = require('../predicates/isSameType')
1310

1411
const Pair = require('./Pair')
1512

1613
const _type =
1714
constant('Arrow')
1815

19-
const _empty =
16+
const _id =
2017
() => Arrow(identity)
2118

2219
function Arrow(runWith) {
@@ -27,18 +24,18 @@ function Arrow(runWith) {
2724
const type =
2825
_type
2926

30-
const empty =
31-
_empty
32-
3327
const value =
3428
constant(runWith)
3529

3630
const inspect =
3731
constant(`Arrow${_inspect(value())}`)
3832

39-
function concat(m) {
33+
const id =
34+
_id
35+
36+
function compose(m) {
4037
if(!(isSameType(Arrow, m))) {
41-
throw new TypeError('Arrow.concat: Arrow required')
38+
throw new TypeError('Arrow.compose: Arrow required')
4239
}
4340

4441
return map(m.runWith)
@@ -49,23 +46,23 @@ function Arrow(runWith) {
4946
throw new TypeError('Arrow.map: Function required')
5047
}
5148

52-
return Arrow(compose(fn, runWith))
49+
return Arrow(composeB(fn, runWith))
5350
}
5451

5552
function contramap(fn) {
5653
if(!isFunction(fn)) {
5754
throw new TypeError('Arrow.contramap: Function required')
5855
}
5956

60-
return Arrow(compose(runWith, fn))
57+
return Arrow(composeB(runWith, fn))
6158
}
6259

6360
function promap(l, r) {
6461
if(!isFunction(l) || !isFunction(r)) {
6562
throw new TypeError('Arrow.promap: Functions required for both arguments')
6663
}
6764

68-
return Arrow(compose(r, runWith, l))
65+
return Arrow(composeB(r, composeB(runWith, l)))
6966
}
7067

7168
function first() {
@@ -98,12 +95,12 @@ function Arrow(runWith) {
9895

9996
return {
10097
inspect, type, value, runWith,
101-
concat, empty, map, contramap,
98+
id, compose, map, contramap,
10299
promap, first, second, both
103100
}
104101
}
105102

106-
Arrow.empty = _empty
103+
Arrow.id = _id
107104
Arrow.type = _type
108105

109106
module.exports = Arrow

crocks/Arrow.spec.js

+18-18
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ test('Arrow', t => {
2020

2121
t.ok(isFunction(Arrow), 'is a function')
2222

23-
t.ok(isFunction(Arrow.empty), 'provides an empty function')
2423
t.ok(isFunction(Arrow.type), 'provides a type function')
24+
t.ok(isFunction(Arrow.id), 'provides an id function')
2525

2626
t.ok(isObject(Arrow(unit)), 'returns an object')
2727

@@ -85,7 +85,7 @@ test('Arrow runWith', t => {
8585
t.end()
8686
})
8787

88-
test('Arrow concat functionality', t => {
88+
test('Arrow compose functionality', t => {
8989
const f = x => x + 1
9090
const g = x => x * 0
9191

@@ -97,7 +97,7 @@ test('Arrow concat functionality', t => {
9797

9898
const notArrow = { type: constant('Arrow...Not') }
9999

100-
const cat = bindFunc(a.concat)
100+
const cat = bindFunc(a.compose)
101101

102102
t.throws(cat(undefined), TypeError, 'throws with undefined')
103103
t.throws(cat(null), TypeError, 'throws with null')
@@ -111,48 +111,48 @@ test('Arrow concat functionality', t => {
111111
t.throws(cat({}), TypeError, 'throws with an object')
112112
t.throws(cat(notArrow), TypeError, 'throws with non-Arrow')
113113

114-
t.same(a.concat(b).runWith(x), result, 'builds composition as expected')
114+
t.same(a.compose(b).runWith(x), result, 'builds composition as expected')
115115

116116
t.end()
117117
})
118118

119-
test('Arrow concat properties (Semigroup)', t => {
119+
test('Arrow compose properties (Semigroupoid)', t => {
120120
const a = Arrow(x => x + 1)
121121
const b = Arrow(x => x * 10)
122122
const c = Arrow(x => x - 5)
123123

124-
t.ok(isFunction(Arrow(identity).concat), 'is a function')
124+
t.ok(isFunction(Arrow(identity).compose), 'is a function')
125125

126-
const left = a.concat(b).concat(c).runWith
127-
const right = a.concat(b.concat(c)).runWith
126+
const left = a.compose(b).compose(c).runWith
127+
const right = a.compose(b.compose(c)).runWith
128128
const x = 20
129129

130130
t.same(left(x), right(x), 'associativity')
131-
t.same(a.concat(b).type(), a.type(), 'returns Semigroup of same type')
131+
t.same(a.compose(b).type(), a.type(), 'returns Semigroupoid of same type')
132132

133133
t.end()
134134
})
135135

136-
test('Arrow empty functionality', t => {
137-
const m = Arrow(unit).empty()
136+
test('Arrow id functionality', t => {
137+
const m = Arrow(unit).id()
138138

139-
t.equal(m.empty, Arrow.empty, 'static and instance versions are the same')
139+
t.equal(m.id, Arrow.id, 'static and instance versions are the same')
140140

141-
t.equal(m.type(), 'Arrow', 'provides an Arrow')
141+
t.equal(m.type(), Arrow.type(), 'provides an Arrow')
142142
t.same(m.runWith(13), 13, 'wraps an identity function')
143143

144144
t.end()
145145
})
146146

147-
test('Arrow empty properties (Monoid)', t => {
147+
test('Arrow id properties (Category)', t => {
148148
const m = Arrow(x => x + 45)
149149
const x = 32
150150

151-
t.ok(isFunction(m.concat), 'provides a concat function')
152-
t.ok(isFunction(m.empty), 'provides a empty function')
151+
t.ok(isFunction(m.compose), 'provides a compose function')
152+
t.ok(isFunction(m.id), 'provides an id function')
153153

154-
const right = m.concat(m.empty()).runWith
155-
const left = m.empty().concat(m).runWith
154+
const right = m.compose(m.id()).runWith
155+
const left = m.id().compose(m).runWith
156156

157157
t.same(right(x), m.runWith(x), 'right identity')
158158
t.same(left(x), m.runWith(x), 'left identity')

crocks/Star.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const isSameType = require('../predicates/isSameType')
88

99
const _inspect = require('../internal/inspect')
1010

11-
const compose = require('../helpers/compose')
11+
const composeB = require('../combinators/composeB')
1212
const constant = require('../combinators/constant')
1313

1414
const merge = require('../pointfree/merge')
@@ -30,7 +30,7 @@ function Star(runWith) {
3030
const inspect =
3131
constant(`Star${_inspect(runWith)}`)
3232

33-
function concat(s) {
33+
function compose(s) {
3434
if(!isSameType(Star, s)) {
3535
throw new TypeError('Star.concat: Star required')
3636
}
@@ -75,7 +75,7 @@ function Star(runWith) {
7575
throw new TypeError('Star.contramap: Function required')
7676
}
7777

78-
return Star(compose(runWith, fn))
78+
return Star(composeB(runWith, fn))
7979
}
8080

8181
function promap(l, r) {
@@ -144,7 +144,7 @@ function Star(runWith) {
144144
}
145145

146146
return {
147-
inspect, type, runWith, concat, map,
147+
inspect, type, runWith, compose, map,
148148
contramap, promap, first, second, both
149149
}
150150
}

crocks/Star.spec.js

+10-10
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,15 @@ test('Star runWith', t => {
7676
t.end()
7777
})
7878

79-
test('Star concat functionality', t => {
79+
test('Star compose functionality', t => {
8080
const f = x => MockCrock(x + 1)
8181

8282
const a = Star(f)
8383

8484
const notStar = { type: constant('Star...Not') }
8585
const notMock = { type: constant('Mock...Not') }
8686

87-
const cat = bindFunc(a.concat)
87+
const cat = bindFunc(a.compose)
8888

8989
t.throws(cat(undefined), TypeError, 'throws with undefined')
9090
t.throws(cat(null), TypeError, 'throws with null')
@@ -98,7 +98,7 @@ test('Star concat functionality', t => {
9898
t.throws(cat({}), TypeError, 'throws with an object')
9999
t.throws(cat(notStar), TypeError, 'throws with non-Star')
100100

101-
const noMonadFst = bindFunc(Star(identity).concat(a).runWith)
101+
const noMonadFst = bindFunc(Star(identity).compose(a).runWith)
102102

103103
t.throws(noMonadFst(undefined), TypeError, 'throws when first computation returns undefined')
104104
t.throws(noMonadFst(null), TypeError, 'throws when first computation returns null')
@@ -111,7 +111,7 @@ test('Star concat functionality', t => {
111111
t.throws(noMonadFst({}), TypeError, 'throws when first computation returns false')
112112
t.throws(noMonadFst([]), TypeError, 'throws when first computation returns true')
113113

114-
const noMonadSnd = bindFunc(x => a.concat(Star(constant(x))).runWith(10))
114+
const noMonadSnd = bindFunc(x => a.compose(Star(constant(x))).runWith(10))
115115

116116
t.throws(noMonadSnd(undefined), TypeError, 'throws when second computation returns undefined')
117117
t.throws(noMonadSnd(null), TypeError, 'throws when second computation returns null')
@@ -129,26 +129,26 @@ test('Star concat functionality', t => {
129129
const g = x => MockCrock(x * 10)
130130

131131
const chained = f(x).chain(g).value()
132-
const star = a.concat(Star(g)).runWith(x).value()
132+
const star = a.compose(Star(g)).runWith(x).value()
133133

134134
t.equal(chained, star, 'builds composition as expected')
135135

136136
t.end()
137137
})
138138

139-
test('Star concat properties (Semigroup)', t => {
139+
test('Star compose properties (Semigroupoid)', t => {
140140
const a = Star(x => MockCrock(x + 1))
141141
const b = Star(x => MockCrock(x * 10))
142142
const c = Star(x => MockCrock(x - 5))
143143

144-
t.ok(isFunction(Star(identity).concat), 'is a function')
144+
t.ok(isFunction(Star(identity).compose), 'is a function')
145145

146-
const left = a.concat(b).concat(c).runWith
147-
const right = a.concat(b.concat(c)).runWith
146+
const left = a.compose(b).compose(c).runWith
147+
const right = a.compose(b.compose(c)).runWith
148148
const x = 20
149149

150150
t.same(left(x).value(), right(x).value(), 'associativity')
151-
t.same(a.concat(b).type(), a.type(), 'returns Semigroup of same type')
151+
t.same(a.compose(b).type(), a.type(), 'returns Semigroupoid of same type')
152152

153153
t.end()
154154
})

helpers/compose.js

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ function applyPipe(f, g) {
1616
return g.call(null, f.apply(null, argsArray(arguments)))
1717
}
1818
}
19+
1920
// compose : ((y -> z), (x -> y), ..., (a -> b)) -> a -> z
2021
function compose() {
2122
if(!arguments.length) {

0 commit comments

Comments
 (0)