版博士V2.0程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Semigroup.js 9.1 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /**
  2. * If a type `A` can form a `Semigroup` it has an **associative** binary operation.
  3. *
  4. * ```ts
  5. * interface Semigroup<A> {
  6. * readonly concat: (x: A, y: A) => A
  7. * }
  8. * ```
  9. *
  10. * Associativity means the following equality must hold for any choice of `x`, `y`, and `z`.
  11. *
  12. * ```ts
  13. * concat(x, concat(y, z)) = concat(concat(x, y), z)
  14. * ```
  15. *
  16. * A common example of a semigroup is the type `string` with the operation `+`.
  17. *
  18. * ```ts
  19. * import { Semigroup } from 'fp-ts/Semigroup'
  20. *
  21. * const semigroupString: Semigroup<string> = {
  22. * concat: (x, y) => x + y
  23. * }
  24. *
  25. * const x = 'x'
  26. * const y = 'y'
  27. * const z = 'z'
  28. *
  29. * semigroupString.concat(x, y) // 'xy'
  30. *
  31. * semigroupString.concat(x, semigroupString.concat(y, z)) // 'xyz'
  32. *
  33. * semigroupString.concat(semigroupString.concat(x, y), z) // 'xyz'
  34. * ```
  35. *
  36. * *Adapted from https://typelevel.org/cats*
  37. *
  38. * @since 2.0.0
  39. */
  40. import { getSemigroup, identity } from './function';
  41. import * as _ from './internal';
  42. import * as M from './Magma';
  43. import * as Or from './Ord';
  44. // -------------------------------------------------------------------------------------
  45. // constructors
  46. // -------------------------------------------------------------------------------------
  47. /**
  48. * Get a semigroup where `concat` will return the minimum, based on the provided order.
  49. *
  50. * @example
  51. * import * as N from 'fp-ts/number'
  52. * import * as S from 'fp-ts/Semigroup'
  53. *
  54. * const S1 = S.min(N.Ord)
  55. *
  56. * assert.deepStrictEqual(S1.concat(1, 2), 1)
  57. *
  58. * @category constructors
  59. * @since 2.10.0
  60. */
  61. export var min = function (O) { return ({
  62. concat: Or.min(O)
  63. }); };
  64. /**
  65. * Get a semigroup where `concat` will return the maximum, based on the provided order.
  66. *
  67. * @example
  68. * import * as N from 'fp-ts/number'
  69. * import * as S from 'fp-ts/Semigroup'
  70. *
  71. * const S1 = S.max(N.Ord)
  72. *
  73. * assert.deepStrictEqual(S1.concat(1, 2), 2)
  74. *
  75. * @category constructors
  76. * @since 2.10.0
  77. */
  78. export var max = function (O) { return ({
  79. concat: Or.max(O)
  80. }); };
  81. /**
  82. * @category constructors
  83. * @since 2.10.0
  84. */
  85. export var constant = function (a) { return ({
  86. concat: function () { return a; }
  87. }); };
  88. // -------------------------------------------------------------------------------------
  89. // combinators
  90. // -------------------------------------------------------------------------------------
  91. /**
  92. * The dual of a `Semigroup`, obtained by swapping the arguments of `concat`.
  93. *
  94. * @example
  95. * import { reverse } from 'fp-ts/Semigroup'
  96. * import * as S from 'fp-ts/string'
  97. *
  98. * assert.deepStrictEqual(reverse(S.Semigroup).concat('a', 'b'), 'ba')
  99. *
  100. * @since 2.10.0
  101. */
  102. export var reverse = M.reverse;
  103. /**
  104. * Given a struct of semigroups returns a semigroup for the struct.
  105. *
  106. * @example
  107. * import { struct } from 'fp-ts/Semigroup'
  108. * import * as N from 'fp-ts/number'
  109. *
  110. * interface Point {
  111. * readonly x: number
  112. * readonly y: number
  113. * }
  114. *
  115. * const S = struct<Point>({
  116. * x: N.SemigroupSum,
  117. * y: N.SemigroupSum
  118. * })
  119. *
  120. * assert.deepStrictEqual(S.concat({ x: 1, y: 2 }, { x: 3, y: 4 }), { x: 4, y: 6 })
  121. *
  122. * @since 2.10.0
  123. */
  124. export var struct = function (semigroups) { return ({
  125. concat: function (first, second) {
  126. var r = {};
  127. for (var k in semigroups) {
  128. if (_.has.call(semigroups, k)) {
  129. r[k] = semigroups[k].concat(first[k], second[k]);
  130. }
  131. }
  132. return r;
  133. }
  134. }); };
  135. /**
  136. * Given a tuple of semigroups returns a semigroup for the tuple.
  137. *
  138. * @example
  139. * import { tuple } from 'fp-ts/Semigroup'
  140. * import * as B from 'fp-ts/boolean'
  141. * import * as N from 'fp-ts/number'
  142. * import * as S from 'fp-ts/string'
  143. *
  144. * const S1 = tuple(S.Semigroup, N.SemigroupSum)
  145. * assert.deepStrictEqual(S1.concat(['a', 1], ['b', 2]), ['ab', 3])
  146. *
  147. * const S2 = tuple(S.Semigroup, N.SemigroupSum, B.SemigroupAll)
  148. * assert.deepStrictEqual(S2.concat(['a', 1, true], ['b', 2, false]), ['ab', 3, false])
  149. *
  150. * @since 2.10.0
  151. */
  152. export var tuple = function () {
  153. var semigroups = [];
  154. for (var _i = 0; _i < arguments.length; _i++) {
  155. semigroups[_i] = arguments[_i];
  156. }
  157. return ({
  158. concat: function (first, second) { return semigroups.map(function (s, i) { return s.concat(first[i], second[i]); }); }
  159. });
  160. };
  161. /**
  162. * Between each pair of elements insert `middle`.
  163. *
  164. * @example
  165. * import { intercalate } from 'fp-ts/Semigroup'
  166. * import * as S from 'fp-ts/string'
  167. * import { pipe } from 'fp-ts/function'
  168. *
  169. * const S1 = pipe(S.Semigroup, intercalate(' + '))
  170. *
  171. * assert.strictEqual(S1.concat('a', 'b'), 'a + b')
  172. *
  173. * @since 2.10.0
  174. */
  175. export var intercalate = function (middle) {
  176. return function (S) { return ({
  177. concat: function (x, y) { return S.concat(x, S.concat(middle, y)); }
  178. }); };
  179. };
  180. // -------------------------------------------------------------------------------------
  181. // instances
  182. // -------------------------------------------------------------------------------------
  183. /**
  184. * Always return the first argument.
  185. *
  186. * @example
  187. * import * as S from 'fp-ts/Semigroup'
  188. *
  189. * assert.deepStrictEqual(S.first<number>().concat(1, 2), 1)
  190. *
  191. * @category instances
  192. * @since 2.10.0
  193. */
  194. export var first = function () { return ({ concat: identity }); };
  195. /**
  196. * Always return the last argument.
  197. *
  198. * @example
  199. * import * as S from 'fp-ts/Semigroup'
  200. *
  201. * assert.deepStrictEqual(S.last<number>().concat(1, 2), 2)
  202. *
  203. * @category instances
  204. * @since 2.10.0
  205. */
  206. export var last = function () { return ({ concat: function (_, y) { return y; } }); };
  207. // -------------------------------------------------------------------------------------
  208. // utils
  209. // -------------------------------------------------------------------------------------
  210. /**
  211. * Given a sequence of `as`, concat them and return the total.
  212. *
  213. * If `as` is empty, return the provided `startWith` value.
  214. *
  215. * @example
  216. * import { concatAll } from 'fp-ts/Semigroup'
  217. * import * as N from 'fp-ts/number'
  218. *
  219. * const sum = concatAll(N.SemigroupSum)(0)
  220. *
  221. * assert.deepStrictEqual(sum([1, 2, 3]), 6)
  222. * assert.deepStrictEqual(sum([]), 0)
  223. *
  224. * @since 2.10.0
  225. */
  226. export var concatAll = M.concatAll;
  227. // -------------------------------------------------------------------------------------
  228. // deprecated
  229. // -------------------------------------------------------------------------------------
  230. /**
  231. * Use `void` module instead.
  232. *
  233. * @category zone of death
  234. * @since 2.0.0
  235. * @deprecated
  236. */
  237. export var semigroupVoid = constant(undefined);
  238. /**
  239. * Use [`getAssignSemigroup`](./struct.ts.html#getAssignSemigroup) instead.
  240. *
  241. * @category zone of death
  242. * @since 2.0.0
  243. * @deprecated
  244. */
  245. export var getObjectSemigroup = function () { return ({
  246. concat: function (first, second) { return Object.assign({}, first, second); }
  247. }); };
  248. /**
  249. * Use [`last`](#last) instead.
  250. *
  251. * @category zone of death
  252. * @since 2.0.0
  253. * @deprecated
  254. */
  255. export var getLastSemigroup = last;
  256. /**
  257. * Use [`first`](#first) instead.
  258. *
  259. * @category zone of death
  260. * @since 2.0.0
  261. * @deprecated
  262. */
  263. export var getFirstSemigroup = first;
  264. /**
  265. * Use [`tuple`](#tuple) instead.
  266. *
  267. * @category zone of death
  268. * @since 2.0.0
  269. * @deprecated
  270. */
  271. export var getTupleSemigroup = tuple;
  272. /**
  273. * Use [`struct`](#struct) instead.
  274. *
  275. * @category zone of death
  276. * @since 2.0.0
  277. * @deprecated
  278. */
  279. export var getStructSemigroup = struct;
  280. /**
  281. * Use [`reverse`](#reverse) instead.
  282. *
  283. * @category zone of death
  284. * @since 2.0.0
  285. * @deprecated
  286. */
  287. export var getDualSemigroup = reverse;
  288. /**
  289. * Use [`max`](#max) instead.
  290. *
  291. * @category zone of death
  292. * @since 2.0.0
  293. * @deprecated
  294. */
  295. export var getJoinSemigroup = max;
  296. /**
  297. * Use [`min`](#min) instead.
  298. *
  299. * @category zone of death
  300. * @since 2.0.0
  301. * @deprecated
  302. */
  303. export var getMeetSemigroup = min;
  304. /**
  305. * Use [`intercalate`](#intercalate) instead.
  306. *
  307. * @category zone of death
  308. * @since 2.5.0
  309. * @deprecated
  310. */
  311. export var getIntercalateSemigroup = intercalate;
  312. export function fold(S) {
  313. var concatAllS = concatAll(S);
  314. return function (startWith, as) { return (as === undefined ? concatAllS(startWith) : concatAllS(startWith)(as)); };
  315. }
  316. /**
  317. * Use [`SemigroupAll`](./boolean.ts.html#SemigroupAll) instead.
  318. *
  319. * @category zone of death
  320. * @since 2.0.0
  321. * @deprecated
  322. */
  323. export var semigroupAll = {
  324. concat: function (x, y) { return x && y; }
  325. };
  326. /**
  327. * Use [`SemigroupAny`](./boolean.ts.html#SemigroupAny) instead.
  328. *
  329. * @category zone of death
  330. * @since 2.0.0
  331. * @deprecated
  332. */
  333. export var semigroupAny = {
  334. concat: function (x, y) { return x || y; }
  335. };
  336. /**
  337. * Use [`getSemigroup`](./function.ts.html#getSemigroup) instead.
  338. *
  339. * @category zone of death
  340. * @since 2.0.0
  341. * @deprecated
  342. */
  343. export var getFunctionSemigroup = getSemigroup;
  344. /**
  345. * Use [`Semigroup`](./string.ts.html#Semigroup) instead.
  346. *
  347. * @category zone of death
  348. * @since 2.0.0
  349. * @deprecated
  350. */
  351. export var semigroupString = {
  352. concat: function (x, y) { return x + y; }
  353. };
  354. /**
  355. * Use [`SemigroupSum`](./number.ts.html#SemigroupSum) instead.
  356. *
  357. * @category zone of death
  358. * @since 2.0.0
  359. * @deprecated
  360. */
  361. export var semigroupSum = {
  362. concat: function (x, y) { return x + y; }
  363. };
  364. /**
  365. * Use [`SemigroupProduct`](./number.ts.html#SemigroupProduct) instead.
  366. *
  367. * @category zone of death
  368. * @since 2.0.0
  369. * @deprecated
  370. */
  371. export var semigroupProduct = {
  372. concat: function (x, y) { return x * y; }
  373. };