版博士V2.0程序
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

430 líneas
12 KiB

  1. import { eqStrict } from './Eq';
  2. import { constant, constTrue, pipe } from './function';
  3. // -------------------------------------------------------------------------------------
  4. // defaults
  5. // -------------------------------------------------------------------------------------
  6. /**
  7. * @category defaults
  8. * @since 2.10.0
  9. */
  10. export var equalsDefault = function (compare) {
  11. return function (first, second) {
  12. return first === second || compare(first, second) === 0;
  13. };
  14. };
  15. // -------------------------------------------------------------------------------------
  16. // constructors
  17. // -------------------------------------------------------------------------------------
  18. /**
  19. * @category constructors
  20. * @since 2.0.0
  21. */
  22. export var fromCompare = function (compare) { return ({
  23. equals: equalsDefault(compare),
  24. compare: function (first, second) { return (first === second ? 0 : compare(first, second)); }
  25. }); };
  26. // -------------------------------------------------------------------------------------
  27. // combinators
  28. // -------------------------------------------------------------------------------------
  29. /**
  30. * Given a tuple of `Ord`s returns an `Ord` for the tuple.
  31. *
  32. * @example
  33. * import { tuple } from 'fp-ts/Ord'
  34. * import * as B from 'fp-ts/boolean'
  35. * import * as S from 'fp-ts/string'
  36. * import * as N from 'fp-ts/number'
  37. *
  38. * const O = tuple(S.Ord, N.Ord, B.Ord)
  39. * assert.strictEqual(O.compare(['a', 1, true], ['b', 2, true]), -1)
  40. * assert.strictEqual(O.compare(['a', 1, true], ['a', 2, true]), -1)
  41. * assert.strictEqual(O.compare(['a', 1, true], ['a', 1, false]), 1)
  42. *
  43. * @since 2.10.0
  44. */
  45. export var tuple = function () {
  46. var ords = [];
  47. for (var _i = 0; _i < arguments.length; _i++) {
  48. ords[_i] = arguments[_i];
  49. }
  50. return fromCompare(function (first, second) {
  51. var i = 0;
  52. for (; i < ords.length - 1; i++) {
  53. var r = ords[i].compare(first[i], second[i]);
  54. if (r !== 0) {
  55. return r;
  56. }
  57. }
  58. return ords[i].compare(first[i], second[i]);
  59. });
  60. };
  61. /**
  62. * @since 2.10.0
  63. */
  64. export var reverse = function (O) { return fromCompare(function (first, second) { return O.compare(second, first); }); };
  65. /* istanbul ignore next */
  66. var contramap_ = function (fa, f) { return pipe(fa, contramap(f)); };
  67. /**
  68. * A typical use case for `contramap` would be like, given some `User` type, to construct an `Ord<User>`.
  69. *
  70. * We can do so with a function from `User -> X` where `X` is some value that we know how to compare
  71. * for ordering (meaning we have an `Ord<X>`)
  72. *
  73. * For example, given the following `User` type, there are lots of possible choices for `X`,
  74. * but let's say we want to sort a list of users by `lastName`.
  75. *
  76. * If we have a way of comparing `lastName`s for ordering (`ordLastName: Ord<string>`) and we know how to go from `User -> string`,
  77. * using `contramap` we can do this
  78. *
  79. * @example
  80. * import { pipe } from 'fp-ts/function'
  81. * import { contramap, Ord } from 'fp-ts/Ord'
  82. * import * as RA from 'fp-ts/ReadonlyArray'
  83. * import * as S from 'fp-ts/string'
  84. *
  85. * interface User {
  86. * readonly firstName: string
  87. * readonly lastName: string
  88. * }
  89. *
  90. * const ordLastName: Ord<string> = S.Ord
  91. *
  92. * const ordByLastName: Ord<User> = pipe(
  93. * ordLastName,
  94. * contramap((user) => user.lastName)
  95. * )
  96. *
  97. * assert.deepStrictEqual(
  98. * RA.sort(ordByLastName)([
  99. * { firstName: 'a', lastName: 'd' },
  100. * { firstName: 'c', lastName: 'b' }
  101. * ]),
  102. * [
  103. * { firstName: 'c', lastName: 'b' },
  104. * { firstName: 'a', lastName: 'd' }
  105. * ]
  106. * )
  107. *
  108. * @since 2.0.0
  109. */
  110. export var contramap = function (f) { return function (fa) {
  111. return fromCompare(function (first, second) { return fa.compare(f(first), f(second)); });
  112. }; };
  113. /**
  114. * @category type lambdas
  115. * @since 2.0.0
  116. */
  117. export var URI = 'Ord';
  118. /**
  119. * A typical use case for the `Semigroup` instance of `Ord` is merging two or more orderings.
  120. *
  121. * For example the following snippet builds an `Ord` for a type `User` which
  122. * sorts by `created` date descending, and **then** `lastName`
  123. *
  124. * @example
  125. * import * as D from 'fp-ts/Date'
  126. * import { pipe } from 'fp-ts/function'
  127. * import { contramap, getSemigroup, Ord, reverse } from 'fp-ts/Ord'
  128. * import * as RA from 'fp-ts/ReadonlyArray'
  129. * import * as S from 'fp-ts/string'
  130. *
  131. * interface User {
  132. * readonly id: string
  133. * readonly lastName: string
  134. * readonly created: Date
  135. * }
  136. *
  137. * const ordByLastName: Ord<User> = pipe(
  138. * S.Ord,
  139. * contramap((user) => user.lastName)
  140. * )
  141. *
  142. * const ordByCreated: Ord<User> = pipe(
  143. * D.Ord,
  144. * contramap((user) => user.created)
  145. * )
  146. *
  147. * const ordUserByCreatedDescThenLastName = getSemigroup<User>().concat(
  148. * reverse(ordByCreated),
  149. * ordByLastName
  150. * )
  151. *
  152. * assert.deepStrictEqual(
  153. * RA.sort(ordUserByCreatedDescThenLastName)([
  154. * { id: 'c', lastName: 'd', created: new Date(1973, 10, 30) },
  155. * { id: 'a', lastName: 'b', created: new Date(1973, 10, 30) },
  156. * { id: 'e', lastName: 'f', created: new Date(1980, 10, 30) }
  157. * ]),
  158. * [
  159. * { id: 'e', lastName: 'f', created: new Date(1980, 10, 30) },
  160. * { id: 'a', lastName: 'b', created: new Date(1973, 10, 30) },
  161. * { id: 'c', lastName: 'd', created: new Date(1973, 10, 30) }
  162. * ]
  163. * )
  164. *
  165. * @category instances
  166. * @since 2.0.0
  167. */
  168. export var getSemigroup = function () { return ({
  169. concat: function (first, second) {
  170. return fromCompare(function (a, b) {
  171. var ox = first.compare(a, b);
  172. return ox !== 0 ? ox : second.compare(a, b);
  173. });
  174. }
  175. }); };
  176. /**
  177. * Returns a `Monoid` such that:
  178. *
  179. * - its `concat(ord1, ord2)` operation will order first by `ord1`, and then by `ord2`
  180. * - its `empty` value is an `Ord` that always considers compared elements equal
  181. *
  182. * @example
  183. * import { sort } from 'fp-ts/Array'
  184. * import { contramap, reverse, getMonoid } from 'fp-ts/Ord'
  185. * import * as S from 'fp-ts/string'
  186. * import * as B from 'fp-ts/boolean'
  187. * import { pipe } from 'fp-ts/function'
  188. * import { concatAll } from 'fp-ts/Monoid'
  189. * import * as N from 'fp-ts/number'
  190. *
  191. * interface User {
  192. * readonly id: number
  193. * readonly name: string
  194. * readonly age: number
  195. * readonly rememberMe: boolean
  196. * }
  197. *
  198. * const byName = pipe(
  199. * S.Ord,
  200. * contramap((p: User) => p.name)
  201. * )
  202. *
  203. * const byAge = pipe(
  204. * N.Ord,
  205. * contramap((p: User) => p.age)
  206. * )
  207. *
  208. * const byRememberMe = pipe(
  209. * B.Ord,
  210. * contramap((p: User) => p.rememberMe)
  211. * )
  212. *
  213. * const M = getMonoid<User>()
  214. *
  215. * const users: Array<User> = [
  216. * { id: 1, name: 'Guido', age: 47, rememberMe: false },
  217. * { id: 2, name: 'Guido', age: 46, rememberMe: true },
  218. * { id: 3, name: 'Giulio', age: 44, rememberMe: false },
  219. * { id: 4, name: 'Giulio', age: 44, rememberMe: true }
  220. * ]
  221. *
  222. * // sort by name, then by age, then by `rememberMe`
  223. * const O1 = concatAll(M)([byName, byAge, byRememberMe])
  224. * assert.deepStrictEqual(sort(O1)(users), [
  225. * { id: 3, name: 'Giulio', age: 44, rememberMe: false },
  226. * { id: 4, name: 'Giulio', age: 44, rememberMe: true },
  227. * { id: 2, name: 'Guido', age: 46, rememberMe: true },
  228. * { id: 1, name: 'Guido', age: 47, rememberMe: false }
  229. * ])
  230. *
  231. * // now `rememberMe = true` first, then by name, then by age
  232. * const O2 = concatAll(M)([reverse(byRememberMe), byName, byAge])
  233. * assert.deepStrictEqual(sort(O2)(users), [
  234. * { id: 4, name: 'Giulio', age: 44, rememberMe: true },
  235. * { id: 2, name: 'Guido', age: 46, rememberMe: true },
  236. * { id: 3, name: 'Giulio', age: 44, rememberMe: false },
  237. * { id: 1, name: 'Guido', age: 47, rememberMe: false }
  238. * ])
  239. *
  240. * @category instances
  241. * @since 2.4.0
  242. */
  243. export var getMonoid = function () { return ({
  244. concat: getSemigroup().concat,
  245. empty: fromCompare(function () { return 0; })
  246. }); };
  247. /**
  248. * @category instances
  249. * @since 2.7.0
  250. */
  251. export var Contravariant = {
  252. URI: URI,
  253. contramap: contramap_
  254. };
  255. // -------------------------------------------------------------------------------------
  256. // utils
  257. // -------------------------------------------------------------------------------------
  258. /**
  259. * @since 2.11.0
  260. */
  261. export var trivial = {
  262. equals: constTrue,
  263. compare: /*#__PURE__*/ constant(0)
  264. };
  265. /**
  266. * @since 2.11.0
  267. */
  268. export var equals = function (O) {
  269. return function (second) {
  270. return function (first) {
  271. return first === second || O.compare(first, second) === 0;
  272. };
  273. };
  274. };
  275. // TODO: curry in v3
  276. /**
  277. * Test whether one value is _strictly less than_ another
  278. *
  279. * @since 2.0.0
  280. */
  281. export var lt = function (O) {
  282. return function (first, second) {
  283. return O.compare(first, second) === -1;
  284. };
  285. };
  286. // TODO: curry in v3
  287. /**
  288. * Test whether one value is _strictly greater than_ another
  289. *
  290. * @since 2.0.0
  291. */
  292. export var gt = function (O) {
  293. return function (first, second) {
  294. return O.compare(first, second) === 1;
  295. };
  296. };
  297. // TODO: curry in v3
  298. /**
  299. * Test whether one value is _non-strictly less than_ another
  300. *
  301. * @since 2.0.0
  302. */
  303. export var leq = function (O) {
  304. return function (first, second) {
  305. return O.compare(first, second) !== 1;
  306. };
  307. };
  308. // TODO: curry in v3
  309. /**
  310. * Test whether one value is _non-strictly greater than_ another
  311. *
  312. * @since 2.0.0
  313. */
  314. export var geq = function (O) {
  315. return function (first, second) {
  316. return O.compare(first, second) !== -1;
  317. };
  318. };
  319. // TODO: curry in v3
  320. /**
  321. * Take the minimum of two values. If they are considered equal, the first argument is chosen
  322. *
  323. * @since 2.0.0
  324. */
  325. export var min = function (O) {
  326. return function (first, second) {
  327. return first === second || O.compare(first, second) < 1 ? first : second;
  328. };
  329. };
  330. // TODO: curry in v3
  331. /**
  332. * Take the maximum of two values. If they are considered equal, the first argument is chosen
  333. *
  334. * @since 2.0.0
  335. */
  336. export var max = function (O) {
  337. return function (first, second) {
  338. return first === second || O.compare(first, second) > -1 ? first : second;
  339. };
  340. };
  341. /**
  342. * Clamp a value between a minimum and a maximum
  343. *
  344. * @since 2.0.0
  345. */
  346. export var clamp = function (O) {
  347. var minO = min(O);
  348. var maxO = max(O);
  349. return function (low, hi) { return function (a) { return maxO(minO(a, hi), low); }; };
  350. };
  351. /**
  352. * Test whether a value is between a minimum and a maximum (inclusive)
  353. *
  354. * @since 2.0.0
  355. */
  356. export var between = function (O) {
  357. var ltO = lt(O);
  358. var gtO = gt(O);
  359. return function (low, hi) { return function (a) { return ltO(a, low) || gtO(a, hi) ? false : true; }; };
  360. };
  361. // -------------------------------------------------------------------------------------
  362. // deprecated
  363. // -------------------------------------------------------------------------------------
  364. /**
  365. * Use [`tuple`](#tuple) instead.
  366. *
  367. * @category zone of death
  368. * @since 2.0.0
  369. * @deprecated
  370. */
  371. export var getTupleOrd = tuple;
  372. /**
  373. * Use [`reverse`](#reverse) instead.
  374. *
  375. * @category zone of death
  376. * @since 2.0.0
  377. * @deprecated
  378. */
  379. export var getDualOrd = reverse;
  380. /**
  381. * Use [`Contravariant`](#contravariant) instead.
  382. *
  383. * @category zone of death
  384. * @since 2.0.0
  385. * @deprecated
  386. */
  387. export var ord = Contravariant;
  388. // default compare for primitive types
  389. function compare(first, second) {
  390. return first < second ? -1 : first > second ? 1 : 0;
  391. }
  392. var strictOrd = {
  393. equals: eqStrict.equals,
  394. compare: compare
  395. };
  396. /**
  397. * Use [`Ord`](./boolean.ts.html#ord) instead.
  398. *
  399. * @category zone of death
  400. * @since 2.0.0
  401. * @deprecated
  402. */
  403. export var ordBoolean = strictOrd;
  404. /**
  405. * Use [`Ord`](./string.ts.html#ord) instead.
  406. *
  407. * @category zone of death
  408. * @since 2.0.0
  409. * @deprecated
  410. */
  411. export var ordString = strictOrd;
  412. /**
  413. * Use [`Ord`](./number.ts.html#ord) instead.
  414. *
  415. * @category zone of death
  416. * @since 2.0.0
  417. * @deprecated
  418. */
  419. export var ordNumber = strictOrd;
  420. /**
  421. * Use [`Ord`](./Date.ts.html#ord) instead.
  422. *
  423. * @category zone of death
  424. * @since 2.0.0
  425. * @deprecated
  426. */
  427. export var ordDate = /*#__PURE__*/ pipe(ordNumber,
  428. /*#__PURE__*/
  429. contramap(function (date) { return date.valueOf(); }));