├── .gitignore
├── README.md
├── dist
├── pointfree.amd.js
└── pointfree.browser.js
├── index.js
├── instances
├── array.js
├── const.js
├── function.js
├── identity.js
├── maybe.js
├── monoids.js
├── string.js
└── sum.js
├── package.json
├── pointfree.js
├── test
├── array.js
├── const.js
├── function.js
├── helper.js
├── identity.js
├── maybe.js
├── monoids.js
└── string.js
└── util.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | tmp
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | pointfree-fantasy
2 | =================
3 |
4 | Point-free wrappers for [fantasy-land](https://github.com/fantasyland/fantasy-land). Functions are curried using
5 | [lodash's curry function](http://lodash.com/docs#curry), and receive their
6 | data last. Gives us aliases with our familar haskell names as well.
7 |
8 | ```js
9 | require('pointfree-fantasy').expose(global); // or if browser pointfree.expose(window)
10 | var Maybe = require('pointfree-fantasy/instances/maybe');
11 |
12 | // setup an easy test fn
13 | var toUpperCase = function(x) { return x.toUpperCase(); };
14 |
15 | map(toUpperCase, Maybe('mystring')) // Just('MYSTRING')
16 | map(toUpperCase, Maybe(null)) // Nothing
17 |
18 | ```
19 |
20 | THE LIST
21 | --------
22 |
23 | * `I` combinator
24 | * `K` combinator
25 | * `compose`, taking arbitrarily many functions
26 | * `map`, aliased `fmap`
27 | * `ap`
28 | * `liftA2`
29 | * `liftA3`
30 | * `chain`, takes chainable first, function last
31 | * `flatMap`, flipped `chain`
32 | * `mjoin`
33 | * `concat`, aliased `mappend`
34 | * `mconcat`, a monoidal reduction.
35 | * `foldMap`
36 | * `fold`
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | Tutorial
46 | ----------
47 | pointfree-fantasy implements a point-free version of the fantasy-land spec, in order to promote a less cluttered, more Haskell-like approach to algebraic programming. We'll justify this approach using Functor as an example.
48 |
49 | In Haskell the Functor typeclass is defined (http://www.haskell.org/haskellwiki/Functor) as:
50 |
51 | ```haskell
52 | class Functor f where
53 | fmap :: (a -> b) -> f a -> f b
54 | ```
55 |
56 | We can read this as:
57 |
58 | f is a Functor if it provides a function fmap
59 | that takes a function from type a to type b
60 | and returns a function from type f a to type f b.
61 |
62 | and the Functor laws are
63 |
64 | ```haskell
65 | fmap id = id
66 | fmap (p . q) = (fmap p) . (fmap q)
67 | ```
68 |
69 | These are the requirements that fmap must satisfy:
70 | fmap of the identity function returns the identity function, and
71 | fmap distributes over function composition.
72 |
73 | (We're usually going to call it map rather than fmap.)
74 |
75 | We can think of a Functor as a container that implements a map function. So if we had a Functor named Container, we'd expect to be able to say
76 |
77 | ```js
78 | Container('hello').map(concat(' world')).map(length);
79 | ```
80 |
81 | and wind up with `Container(11)`. As long as each function works on the *content* of the Container, mapping the function over the Container will return a Container with the transformed content.
82 |
83 | Notice that the type of the content will change if the mapped function returns a different type, as with `length` above. So a Functor has to be able to contain any type.
84 |
85 | Or as Julian Birch says:
86 |
87 | > So what the heck is a functor? Well, really it's just something you can map over and it makes sense.
88 |
89 | We haven't mentioned any specific Functors yet. It's the particular things that each different Functor can do that distinguish them from one another. Usually these particular things have to do with how you access the values in the container. The Functor laws, and the clean ways they help us to manipulate Functors, are what all Functors have in common.
90 |
91 | Take a look at Birch's little list of [things you can map over](http://web.archive.org/web/20150918214956/http://www.colourcoding.net/blog/archive/2014/06/27/not-a-haskell-monad-tutorial-functors.aspx).
92 |
93 |
94 | -------------------------------
95 |
96 |
97 | Our most common Functor in JavaScript is Array. Of course Array is normally written as a pair of square brackets around the value(s) it's operating on, but we can imagine it as an explicit function, namely the Array constructor, instead. (Also imagine that the Array constructor does not have special-case behavior when passed a single argument!)
98 |
99 | Also note that we're considering Arrays whose contents are all of a single type. The VALUE of an Array is a sequence of values of that underlying type. MAPPING a function f (such as the function "+1") over an Array produces a new Array whose value is a sequence of underlying values, each value equal to f(x), or "+1" of the original. In code:
100 |
101 | `Array(2,3,4).map(function(n){ return n + 1; }) // Array(3,4,5)`
102 |
103 | The fmap function for Array, conveniently, is the similarly-named Array.prototype.map.
104 |
105 | Does it satisfy the Functor laws?
106 |
107 |
108 | Let's see how fantasy-land expresses the Functor laws (https://github.com/fantasyland/fantasy-land#functor):
109 |
110 | ```js
111 | u.map(function(a) { return a; }) // is equivalent to u (identity)
112 | u.map(function(x) { return f(g(x)); }) // is equivalent to u.map(g).map(f) (composition)
113 | ```
114 |
115 | You can verify these pretty easily.
116 |
117 | But notice that the laws have gotten a bit more prolix. Of course, once we define
118 |
119 | ```js
120 | var id = function(a) { return a; };
121 | var compose = function(f, g) { return function(x) { return f(g(x)); }};
122 | ```
123 |
124 | they become
125 |
126 | ```js
127 | u.map(id) == u
128 | u.map(compose(f, g)) == u.map(g).map(f)
129 | ```
130 |
131 | This is neater, but we also want to avoid mentioning that u! We want to speak of standalone functions, not methods, and so we provide a map function that's NOT defined on Array.prototype. Here's why:
132 |
133 | If you have a function that works on a single value and you want to transform it to work on some functor, say Array, you can call map on your function like this: `map(f)`
134 |
135 | ```js
136 | funnyFortune = function(x){
137 | return x + ' in bed';
138 | };
139 | ```
140 |
141 | `var worksOnArrayFortune = map(funnyFortune)`
142 |
143 | This saves you from having to type
144 |
145 | ```js
146 | var worksOnArrayFortune = function(xs){
147 | return xs.map(funnyFortune);
148 | };
149 | ```
150 |
151 | In fact you may not need to define `worksOnArrayFortune` at all,
152 | since you can simply say map(funnyFortune) inline when you need it.
153 |
154 | And this works for every Functor, not just Array! We'll be talking soon enough about other Functors you may already be using.
155 |
156 | With this and compose, the laws become
157 |
158 | ```js
159 | map(id) == id
160 | map(compose(f, g)) == compose(map(f), map(g))
161 | ```
162 |
163 | Composing functions without explicitly mentioning their arguments is what we call "point-free style." The "points" in question are the actual values. In topology, where the term originated, the values are always points!
164 |
165 |
166 |
167 |
168 | ...............................
169 |
170 | Now let's look at a more practical example.
171 |
172 | We're fetching rows from a database, formatting what we want from each one, and displaying them on the screen.
173 | Say we have three functions:
174 |
175 | getRows, which takes an Int and returns an Array of Rows:
176 |
177 | ```js
178 | //+ getRows :: Int -> [Row]
179 | getRows = function(i) { return db.getSomeRows(i); };
180 | ```
181 |
182 | renderRow, which takes a Row and returns a snippet of Html:
183 |
184 | ```js
185 | //+ renderRow :: Row -> Html
186 | renderRow = function(row) {
187 | return '
' + row.title + '
'
188 | };
189 | ```
190 |
191 | and drawOnScreen, which takes an Array of Html snippets and returns a Dom tree:
192 |
193 | ```js
194 | //+ drawOnScreen :: [Html] -> Dom
195 | // you supply the code
196 | ```
197 |
198 | From these bite-size pieces, each responsible for doing its own little job,
199 | we use compose and map to build up our program:
200 |
201 | ```js
202 | //+ prog: Int -> Dom
203 | prog = compose(drawOnScreen, map(renderRow), getRows);
204 | ```
205 |
206 | Notice that when we compose functions, the data flows from right to left:
207 | getRows takes in an Int and feeds an Array of Rows to the left,
208 | where we use map to convert renderRow into a function that takes in that Array of Rows and feeds an Array of Html snippets to the left,
209 | where drawOnScreen is ready to accept it and produce the Dom.
210 | Here's how we think about it in terms of the type signatures, showing the same data flow from left to right:
211 |
212 |
213 | ```
214 | //+ getRows :: Int -> [Row]
215 | //+ map(renderRow) :: [Row] -> [Html]
216 | //+ drawOnScreen :: [Html] -> Dom
217 | //-------------------------------------------------
218 | //+ prog :: Int -> Dom
219 | ```
220 |
221 | Haskell would be keeping track of the types for us and stopping us if we slip up,
222 | but in JavaScript it's up to us to manage them. That's why we always try to annotate our functions with these comments.
223 |
224 |
225 | ----------------------------
226 |
227 | Now shit's about to get realer because we need to fetch the rows asynchronously from a remote database! For this we're going to use our next Functor: Future. The VALUE of a Future is the actions that will produce the underlying value. That underlying value might be an Array of Rows, or it might be the Dom. Once we have our Future, it provides a way to actually run those actions and resolve to the underlying value, but in the meantime we can compose and map until we're satisfied with how we've constructed the pure Future. MAPPING a function f over a Future that will resolve to a value x produces a new Future that will resolve to the value f(x).
228 |
229 | (Future is defined in folktale's data.future repository (#!https://github.com/folktale/data.future).
230 | fantasyland-pointfree incorporates functions that work the way we like
231 | from several external libraries, and Future is one.)
232 |
233 | We revise getRows to return a Future of an Array of Rows:
234 |
235 | ```js
236 | //+ getRows :: Int -> Future([Row])
237 | getRows = function(i){
238 | return new Future(function(reject, resolve) {
239 | resolve(i + ' rows from the database');
240 | });
241 | };
242 | ```
243 |
244 | and our program becomes:
245 |
246 | ```
247 | //+ getRows :: Int -> Future([Row])
248 | //+ map(map(renderRow)) :: Future([Row]) -> Future([Html])
249 | //+ map(drawOnScreen) :: Future([Html]) -> Future(Dom)
250 | //------------------------------------------------------------------------------
251 | //+ prog :: Int -> Future(Dom)
252 | ```
253 |
254 | ```js
255 | //+ prog :: Int -> Future(Dom)
256 | prog = compose(map(drawOnScreen), map(map(renderRow)), getRows)
257 | ```
258 |
259 | In a bit we'll cause the Future(Dom) to run its actions and resolve to that Dom object, but first let's unpack this a bit. We've mentioned that map(f) does the same thing conceptually over any Functor: transform the Functor into the corresponding Functor whose underlying value(s) are f(x). But when we say `map(map(renderRow))`, you might ask how HAL knows which map is which. (Besides from reading your lips.) Map is polymorphic, and if we look at its definition, we'll see how that is implemented:
260 |
261 | ```js
262 | map = _.curry(function(f, obj){ return obj.map(f); })
263 | ```
264 |
265 | Map simply delegates to the member function .map on whatever object it receives as its second argument. This allows us to partially apply it with the first argument f. The second argument, the one that determines which .map implementation will be called, is passed in from the right along the chain of composition. So the outer map of `map(map(renderRow))` will receive the Future from getRows, and the inner map will receive the Array of Rows inside the Future:
266 |
267 | ```js
268 | //+ map(map(renderRow), future_of_rows) :: Future([Row]) -> Future([Html])
269 | //+ map(renderRow, rows) :: [Row] -> [Html]
270 | ```
271 |
272 | (If you want to hear more about currying, see the talk [Hey Underscore, You're Doing It Wrong!](http://www.youtube.com/watch?v=m3svKOdZijA).
273 |
274 |
275 | Future has a method `fork` that runs its actions and resolves to its underlying value, so we can invoke our prog like this:
276 |
277 | ```js
278 | prog(2).fork(function(err){}, function(result){}) // see folktale
279 | ```
280 |
281 | and the page displaying two rows will be drawn when the Future's underlying value is realized.
282 |
283 |
284 |
285 |
286 | Now let's see how the laws help us do a bit of refactoring.
287 |
288 |
289 | - we remember compose is associative so we can simplify our prog with a helper
290 | (This comes not from the Functor laws but from the fact that functions form a category; see below):
291 |
292 |
293 | ```js
294 | //+ makePage :: Future([Row]) -> Future(Dom)
295 | makePage = compose(map(drawOnScreen), map(map(renderRow)));
296 |
297 | prog = compose(makePage, getRows);
298 | ```
299 |
300 | - we remember our law: `compose(map(f), map(g)) == map(compose(f, g))`, so we factor out a map just like we do in oh, I don't know, ALGEBRA?:
301 |
302 |
303 | ```js
304 | //+ makePage :: Future([Row]) -> Future(Dom)
305 | makePage = map(compose(drawOnScreen, map(renderRow)));
306 |
307 | prog = compose(makePage, getRows);
308 | ```
309 |
310 | - finally we notice we'd rather have makePage work on simpler types than Futures:
311 |
312 |
313 | ```js
314 | //+ makePage :: [Row] -> Dom
315 | makePage = compose(drawOnScreen, map(renderRow));
316 |
317 | prog = compose(map(makePage), getRows);
318 | ```
319 |
320 |
321 |
322 | You will have noticed that as we manipulate functions with map and compose, we are exactly paralleling the way we manipulate variables with addition and multiplication; hence the term *algebra*.
323 |
324 | ```js
325 | (x + y) + z == x + (y + z) == add(x, y, z)
326 | compose(compose(f, g), h) == compose(f, compose(g, h)) == compose(f, g, h)
327 | ```
328 |
329 | ```js
330 | add(mul(2, 4), mul(2,3)) == mul(add(4, 3), 2)
331 | compose(map(f), map(g)) == map(compose(f, g))
332 | ```
333 |
334 |
335 |
--------------------------------------------------------------------------------
/dist/pointfree.amd.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o
167 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
168 | * Copyright 2012-2013 The Dojo Foundation
169 | * Based on Underscore.js 1.5.2
170 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
171 | * Available under MIT license
172 | */
173 | var createWrapper = require('lodash._createwrapper');
174 |
175 | /**
176 | * Creates a function which accepts one or more arguments of `func` that when
177 | * invoked either executes `func` returning its result, if all `func` arguments
178 | * have been provided, or returns a function that accepts one or more of the
179 | * remaining `func` arguments, and so on. The arity of `func` can be specified
180 | * if `func.length` is not sufficient.
181 | *
182 | * @static
183 | * @memberOf _
184 | * @category Functions
185 | * @param {Function} func The function to curry.
186 | * @param {number} [arity=func.length] The arity of `func`.
187 | * @returns {Function} Returns the new curried function.
188 | * @example
189 | *
190 | * var curried = _.curry(function(a, b, c) {
191 | * console.log(a + b + c);
192 | * });
193 | *
194 | * curried(1)(2)(3);
195 | * // => 6
196 | *
197 | * curried(1, 2)(3);
198 | * // => 6
199 | *
200 | * curried(1, 2, 3);
201 | * // => 6
202 | */
203 | function curry(func, arity) {
204 | arity = typeof arity == 'number' ? arity : (+arity || func.length);
205 | return createWrapper(func, 4, null, null, null, arity);
206 | }
207 |
208 | module.exports = curry;
209 |
210 | },{"lodash._createwrapper":5}],5:[function(require,module,exports){
211 | /**
212 | * Lo-Dash 2.4.1 (Custom Build)
213 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
214 | * Copyright 2012-2013 The Dojo Foundation
215 | * Based on Underscore.js 1.5.2
216 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
217 | * Available under MIT license
218 | */
219 | var baseBind = require('lodash._basebind'),
220 | baseCreateWrapper = require('lodash._basecreatewrapper'),
221 | isFunction = require('lodash.isfunction'),
222 | slice = require('lodash._slice');
223 |
224 | /**
225 | * Used for `Array` method references.
226 | *
227 | * Normally `Array.prototype` would suffice, however, using an array literal
228 | * avoids issues in Narwhal.
229 | */
230 | var arrayRef = [];
231 |
232 | /** Native method shortcuts */
233 | var push = arrayRef.push,
234 | unshift = arrayRef.unshift;
235 |
236 | /**
237 | * Creates a function that, when called, either curries or invokes `func`
238 | * with an optional `this` binding and partially applied arguments.
239 | *
240 | * @private
241 | * @param {Function|string} func The function or method name to reference.
242 | * @param {number} bitmask The bitmask of method flags to compose.
243 | * The bitmask may be composed of the following flags:
244 | * 1 - `_.bind`
245 | * 2 - `_.bindKey`
246 | * 4 - `_.curry`
247 | * 8 - `_.curry` (bound)
248 | * 16 - `_.partial`
249 | * 32 - `_.partialRight`
250 | * @param {Array} [partialArgs] An array of arguments to prepend to those
251 | * provided to the new function.
252 | * @param {Array} [partialRightArgs] An array of arguments to append to those
253 | * provided to the new function.
254 | * @param {*} [thisArg] The `this` binding of `func`.
255 | * @param {number} [arity] The arity of `func`.
256 | * @returns {Function} Returns the new function.
257 | */
258 | function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
259 | var isBind = bitmask & 1,
260 | isBindKey = bitmask & 2,
261 | isCurry = bitmask & 4,
262 | isCurryBound = bitmask & 8,
263 | isPartial = bitmask & 16,
264 | isPartialRight = bitmask & 32;
265 |
266 | if (!isBindKey && !isFunction(func)) {
267 | throw new TypeError;
268 | }
269 | if (isPartial && !partialArgs.length) {
270 | bitmask &= ~16;
271 | isPartial = partialArgs = false;
272 | }
273 | if (isPartialRight && !partialRightArgs.length) {
274 | bitmask &= ~32;
275 | isPartialRight = partialRightArgs = false;
276 | }
277 | var bindData = func && func.__bindData__;
278 | if (bindData && bindData !== true) {
279 | // clone `bindData`
280 | bindData = slice(bindData);
281 | if (bindData[2]) {
282 | bindData[2] = slice(bindData[2]);
283 | }
284 | if (bindData[3]) {
285 | bindData[3] = slice(bindData[3]);
286 | }
287 | // set `thisBinding` is not previously bound
288 | if (isBind && !(bindData[1] & 1)) {
289 | bindData[4] = thisArg;
290 | }
291 | // set if previously bound but not currently (subsequent curried functions)
292 | if (!isBind && bindData[1] & 1) {
293 | bitmask |= 8;
294 | }
295 | // set curried arity if not yet set
296 | if (isCurry && !(bindData[1] & 4)) {
297 | bindData[5] = arity;
298 | }
299 | // append partial left arguments
300 | if (isPartial) {
301 | push.apply(bindData[2] || (bindData[2] = []), partialArgs);
302 | }
303 | // append partial right arguments
304 | if (isPartialRight) {
305 | unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
306 | }
307 | // merge flags
308 | bindData[1] |= bitmask;
309 | return createWrapper.apply(null, bindData);
310 | }
311 | // fast path for `_.bind`
312 | var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
313 | return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
314 | }
315 |
316 | module.exports = createWrapper;
317 |
318 | },{"lodash._basebind":6,"lodash._basecreatewrapper":15,"lodash._slice":24,"lodash.isfunction":25}],6:[function(require,module,exports){
319 | /**
320 | * Lo-Dash 2.4.1 (Custom Build)
321 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
322 | * Copyright 2012-2013 The Dojo Foundation
323 | * Based on Underscore.js 1.5.2
324 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
325 | * Available under MIT license
326 | */
327 | var baseCreate = require('lodash._basecreate'),
328 | isObject = require('lodash.isobject'),
329 | setBindData = require('lodash._setbinddata'),
330 | slice = require('lodash._slice');
331 |
332 | /**
333 | * Used for `Array` method references.
334 | *
335 | * Normally `Array.prototype` would suffice, however, using an array literal
336 | * avoids issues in Narwhal.
337 | */
338 | var arrayRef = [];
339 |
340 | /** Native method shortcuts */
341 | var push = arrayRef.push;
342 |
343 | /**
344 | * The base implementation of `_.bind` that creates the bound function and
345 | * sets its meta data.
346 | *
347 | * @private
348 | * @param {Array} bindData The bind data array.
349 | * @returns {Function} Returns the new bound function.
350 | */
351 | function baseBind(bindData) {
352 | var func = bindData[0],
353 | partialArgs = bindData[2],
354 | thisArg = bindData[4];
355 |
356 | function bound() {
357 | // `Function#bind` spec
358 | // http://es5.github.io/#x15.3.4.5
359 | if (partialArgs) {
360 | // avoid `arguments` object deoptimizations by using `slice` instead
361 | // of `Array.prototype.slice.call` and not assigning `arguments` to a
362 | // variable as a ternary expression
363 | var args = slice(partialArgs);
364 | push.apply(args, arguments);
365 | }
366 | // mimic the constructor's `return` behavior
367 | // http://es5.github.io/#x13.2.2
368 | if (this instanceof bound) {
369 | // ensure `new bound` is an instance of `func`
370 | var thisBinding = baseCreate(func.prototype),
371 | result = func.apply(thisBinding, args || arguments);
372 | return isObject(result) ? result : thisBinding;
373 | }
374 | return func.apply(thisArg, args || arguments);
375 | }
376 | setBindData(bound, bindData);
377 | return bound;
378 | }
379 |
380 | module.exports = baseBind;
381 |
382 | },{"lodash._basecreate":7,"lodash._setbinddata":10,"lodash._slice":24,"lodash.isobject":13}],7:[function(require,module,exports){
383 | var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/**
384 | * Lo-Dash 2.4.1 (Custom Build)
385 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
386 | * Copyright 2012-2013 The Dojo Foundation
387 | * Based on Underscore.js 1.5.2
388 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
389 | * Available under MIT license
390 | */
391 | var isNative = require('lodash._isnative'),
392 | isObject = require('lodash.isobject'),
393 | noop = require('lodash.noop');
394 |
395 | /* Native method shortcuts for methods with the same name as other `lodash` methods */
396 | var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate;
397 |
398 | /**
399 | * The base implementation of `_.create` without support for assigning
400 | * properties to the created object.
401 | *
402 | * @private
403 | * @param {Object} prototype The object to inherit from.
404 | * @returns {Object} Returns the new object.
405 | */
406 | function baseCreate(prototype, properties) {
407 | return isObject(prototype) ? nativeCreate(prototype) : {};
408 | }
409 | // fallback for browsers without `Object.create`
410 | if (!nativeCreate) {
411 | baseCreate = (function() {
412 | function Object() {}
413 | return function(prototype) {
414 | if (isObject(prototype)) {
415 | Object.prototype = prototype;
416 | var result = new Object;
417 | Object.prototype = null;
418 | }
419 | return result || global.Object();
420 | };
421 | }());
422 | }
423 |
424 | module.exports = baseCreate;
425 |
426 | },{"lodash._isnative":8,"lodash.isobject":13,"lodash.noop":9}],8:[function(require,module,exports){
427 | /**
428 | * Lo-Dash 2.4.1 (Custom Build)
429 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
430 | * Copyright 2012-2013 The Dojo Foundation
431 | * Based on Underscore.js 1.5.2
432 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
433 | * Available under MIT license
434 | */
435 |
436 | /** Used for native method references */
437 | var objectProto = Object.prototype;
438 |
439 | /** Used to resolve the internal [[Class]] of values */
440 | var toString = objectProto.toString;
441 |
442 | /** Used to detect if a method is native */
443 | var reNative = RegExp('^' +
444 | String(toString)
445 | .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
446 | .replace(/toString| for [^\]]+/g, '.*?') + '$'
447 | );
448 |
449 | /**
450 | * Checks if `value` is a native function.
451 | *
452 | * @private
453 | * @param {*} value The value to check.
454 | * @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
455 | */
456 | function isNative(value) {
457 | return typeof value == 'function' && reNative.test(value);
458 | }
459 |
460 | module.exports = isNative;
461 |
462 | },{}],9:[function(require,module,exports){
463 | /**
464 | * Lo-Dash 2.4.1 (Custom Build)
465 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
466 | * Copyright 2012-2013 The Dojo Foundation
467 | * Based on Underscore.js 1.5.2
468 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
469 | * Available under MIT license
470 | */
471 |
472 | /**
473 | * A no-operation function.
474 | *
475 | * @static
476 | * @memberOf _
477 | * @category Utilities
478 | * @example
479 | *
480 | * var object = { 'name': 'fred' };
481 | * _.noop(object) === undefined;
482 | * // => true
483 | */
484 | function noop() {
485 | // no operation performed
486 | }
487 |
488 | module.exports = noop;
489 |
490 | },{}],10:[function(require,module,exports){
491 | /**
492 | * Lo-Dash 2.4.1 (Custom Build)
493 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
494 | * Copyright 2012-2013 The Dojo Foundation
495 | * Based on Underscore.js 1.5.2
496 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
497 | * Available under MIT license
498 | */
499 | var isNative = require('lodash._isnative'),
500 | noop = require('lodash.noop');
501 |
502 | /** Used as the property descriptor for `__bindData__` */
503 | var descriptor = {
504 | 'configurable': false,
505 | 'enumerable': false,
506 | 'value': null,
507 | 'writable': false
508 | };
509 |
510 | /** Used to set meta data on functions */
511 | var defineProperty = (function() {
512 | // IE 8 only accepts DOM elements
513 | try {
514 | var o = {},
515 | func = isNative(func = Object.defineProperty) && func,
516 | result = func(o, o, o) && func;
517 | } catch(e) { }
518 | return result;
519 | }());
520 |
521 | /**
522 | * Sets `this` binding data on a given function.
523 | *
524 | * @private
525 | * @param {Function} func The function to set data on.
526 | * @param {Array} value The data array to set.
527 | */
528 | var setBindData = !defineProperty ? noop : function(func, value) {
529 | descriptor.value = value;
530 | defineProperty(func, '__bindData__', descriptor);
531 | };
532 |
533 | module.exports = setBindData;
534 |
535 | },{"lodash._isnative":11,"lodash.noop":12}],11:[function(require,module,exports){
536 | module.exports=require(8)
537 | },{}],12:[function(require,module,exports){
538 | module.exports=require(9)
539 | },{}],13:[function(require,module,exports){
540 | /**
541 | * Lo-Dash 2.4.1 (Custom Build)
542 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
543 | * Copyright 2012-2013 The Dojo Foundation
544 | * Based on Underscore.js 1.5.2
545 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
546 | * Available under MIT license
547 | */
548 | var objectTypes = require('lodash._objecttypes');
549 |
550 | /**
551 | * Checks if `value` is the language type of Object.
552 | * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
553 | *
554 | * @static
555 | * @memberOf _
556 | * @category Objects
557 | * @param {*} value The value to check.
558 | * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
559 | * @example
560 | *
561 | * _.isObject({});
562 | * // => true
563 | *
564 | * _.isObject([1, 2, 3]);
565 | * // => true
566 | *
567 | * _.isObject(1);
568 | * // => false
569 | */
570 | function isObject(value) {
571 | // check if the value is the ECMAScript language type of Object
572 | // http://es5.github.io/#x8
573 | // and avoid a V8 bug
574 | // http://code.google.com/p/v8/issues/detail?id=2291
575 | return !!(value && objectTypes[typeof value]);
576 | }
577 |
578 | module.exports = isObject;
579 |
580 | },{"lodash._objecttypes":14}],14:[function(require,module,exports){
581 | /**
582 | * Lo-Dash 2.4.1 (Custom Build)
583 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
584 | * Copyright 2012-2013 The Dojo Foundation
585 | * Based on Underscore.js 1.5.2
586 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
587 | * Available under MIT license
588 | */
589 |
590 | /** Used to determine if values are of the language type Object */
591 | var objectTypes = {
592 | 'boolean': false,
593 | 'function': true,
594 | 'object': true,
595 | 'number': false,
596 | 'string': false,
597 | 'undefined': false
598 | };
599 |
600 | module.exports = objectTypes;
601 |
602 | },{}],15:[function(require,module,exports){
603 | /**
604 | * Lo-Dash 2.4.1 (Custom Build)
605 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
606 | * Copyright 2012-2013 The Dojo Foundation
607 | * Based on Underscore.js 1.5.2
608 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
609 | * Available under MIT license
610 | */
611 | var baseCreate = require('lodash._basecreate'),
612 | isObject = require('lodash.isobject'),
613 | setBindData = require('lodash._setbinddata'),
614 | slice = require('lodash._slice');
615 |
616 | /**
617 | * Used for `Array` method references.
618 | *
619 | * Normally `Array.prototype` would suffice, however, using an array literal
620 | * avoids issues in Narwhal.
621 | */
622 | var arrayRef = [];
623 |
624 | /** Native method shortcuts */
625 | var push = arrayRef.push;
626 |
627 | /**
628 | * The base implementation of `createWrapper` that creates the wrapper and
629 | * sets its meta data.
630 | *
631 | * @private
632 | * @param {Array} bindData The bind data array.
633 | * @returns {Function} Returns the new function.
634 | */
635 | function baseCreateWrapper(bindData) {
636 | var func = bindData[0],
637 | bitmask = bindData[1],
638 | partialArgs = bindData[2],
639 | partialRightArgs = bindData[3],
640 | thisArg = bindData[4],
641 | arity = bindData[5];
642 |
643 | var isBind = bitmask & 1,
644 | isBindKey = bitmask & 2,
645 | isCurry = bitmask & 4,
646 | isCurryBound = bitmask & 8,
647 | key = func;
648 |
649 | function bound() {
650 | var thisBinding = isBind ? thisArg : this;
651 | if (partialArgs) {
652 | var args = slice(partialArgs);
653 | push.apply(args, arguments);
654 | }
655 | if (partialRightArgs || isCurry) {
656 | args || (args = slice(arguments));
657 | if (partialRightArgs) {
658 | push.apply(args, partialRightArgs);
659 | }
660 | if (isCurry && args.length < arity) {
661 | bitmask |= 16 & ~32;
662 | return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
663 | }
664 | }
665 | args || (args = arguments);
666 | if (isBindKey) {
667 | func = thisBinding[key];
668 | }
669 | if (this instanceof bound) {
670 | thisBinding = baseCreate(func.prototype);
671 | var result = func.apply(thisBinding, args);
672 | return isObject(result) ? result : thisBinding;
673 | }
674 | return func.apply(thisBinding, args);
675 | }
676 | setBindData(bound, bindData);
677 | return bound;
678 | }
679 |
680 | module.exports = baseCreateWrapper;
681 |
682 | },{"lodash._basecreate":16,"lodash._setbinddata":19,"lodash._slice":24,"lodash.isobject":22}],16:[function(require,module,exports){
683 | arguments[4][7][0].apply(exports,arguments)
684 | },{"lodash._isnative":17,"lodash.isobject":22,"lodash.noop":18}],17:[function(require,module,exports){
685 | module.exports=require(8)
686 | },{}],18:[function(require,module,exports){
687 | module.exports=require(9)
688 | },{}],19:[function(require,module,exports){
689 | module.exports=require(10)
690 | },{"lodash._isnative":20,"lodash.noop":21}],20:[function(require,module,exports){
691 | module.exports=require(8)
692 | },{}],21:[function(require,module,exports){
693 | module.exports=require(9)
694 | },{}],22:[function(require,module,exports){
695 | module.exports=require(13)
696 | },{"lodash._objecttypes":23}],23:[function(require,module,exports){
697 | module.exports=require(14)
698 | },{}],24:[function(require,module,exports){
699 | /**
700 | * Lo-Dash 2.4.1 (Custom Build)
701 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
702 | * Copyright 2012-2013 The Dojo Foundation
703 | * Based on Underscore.js 1.5.2
704 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
705 | * Available under MIT license
706 | */
707 |
708 | /**
709 | * Slices the `collection` from the `start` index up to, but not including,
710 | * the `end` index.
711 | *
712 | * Note: This function is used instead of `Array#slice` to support node lists
713 | * in IE < 9 and to ensure dense arrays are returned.
714 | *
715 | * @private
716 | * @param {Array|Object|string} collection The collection to slice.
717 | * @param {number} start The start index.
718 | * @param {number} end The end index.
719 | * @returns {Array} Returns the new array.
720 | */
721 | function slice(array, start, end) {
722 | start || (start = 0);
723 | if (typeof end == 'undefined') {
724 | end = array ? array.length : 0;
725 | }
726 | var index = -1,
727 | length = end - start || 0,
728 | result = Array(length < 0 ? 0 : length);
729 |
730 | while (++index < length) {
731 | result[index] = array[start + index];
732 | }
733 | return result;
734 | }
735 |
736 | module.exports = slice;
737 |
738 | },{}],25:[function(require,module,exports){
739 | /**
740 | * Lo-Dash 2.4.1 (Custom Build)
741 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
742 | * Copyright 2012-2013 The Dojo Foundation
743 | * Based on Underscore.js 1.5.2
744 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
745 | * Available under MIT license
746 | */
747 |
748 | /**
749 | * Checks if `value` is a function.
750 | *
751 | * @static
752 | * @memberOf _
753 | * @category Objects
754 | * @param {*} value The value to check.
755 | * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
756 | * @example
757 | *
758 | * _.isFunction(_);
759 | * // => true
760 | */
761 | function isFunction(value) {
762 | return typeof value == 'function';
763 | }
764 |
765 | module.exports = isFunction;
766 |
767 | },{}],26:[function(require,module,exports){
768 | var curry = require('lodash.curry');
769 |
770 | var BUILT_INS = { 'array': require('./instances/array')
771 | , 'function': require('./instances/function')
772 | , 'string': require('./instances/string')
773 | }
774 |
775 | var _groupsOf = curry(function(n, xs) {
776 | if(!xs.length) return [];
777 | return [xs.slice(0, n)].concat(_groupsOf(n, xs.slice(n, xs.length)));
778 | });
779 |
780 | var _compose = curry(function(f,g,x) { return f(g(x)) });
781 |
782 | var I = function(x){ return x; }
783 |
784 | // f . g . h == compose(f, g, h)
785 | var toAssociativeCommaInfix = function(fn) {
786 | return function() {
787 | var fns = [].slice.call(arguments)
788 | return function() {
789 | return _groupsOf(2, fns).reverse().map(function(g) {
790 | return (g.length > 1) ? fn.apply(this,g) : g[0];
791 | }).reduce(function(x, f) {
792 | return [f.apply(f,x)];
793 | }, arguments)[0];
794 | };
795 | };
796 | };
797 |
798 | var compose = toAssociativeCommaInfix(_compose);
799 |
800 |
801 | var pointy = {};
802 |
803 | var id = function(x) { return x; }
804 | var K = function(x) { return function(){ return x; } }
805 |
806 | var map = curry(function(f, u) {
807 | return u.fmap ? u.fmap(f) : u.map(f); //sometimes map passes index so we use fmap if it has it.
808 | });
809 |
810 | var ap = curry(function(a1, a2) {
811 | return a1.ap(a2);
812 | });
813 |
814 | var liftA2 = curry(function(f, x, y) {
815 | return map(f,x).ap(y);
816 | });
817 |
818 | var liftA3 = curry(function(f, x, y, z) {
819 | return map(f, x).ap(y).ap(z);
820 | });
821 |
822 | var chain = curry(function(f, mv) {
823 | return mv.chain(f);
824 | });
825 |
826 | var mjoin = function(mmv) {
827 | return chain(id, mmv);
828 | };
829 |
830 | var concat = curry(function(x, y) {
831 | return x.concat(y);
832 | });
833 |
834 | var mconcat = function(xs, empty) {
835 | return xs.length ? xs.reduce(concat) : empty();
836 | };
837 |
838 | var sequenceA = curry(function(point, fctr) {
839 | return fctr.traverse(id, point);
840 | });
841 |
842 | var of = function(x) {
843 | return x.of;
844 | };
845 |
846 | var traverse = curry(function(f, point, fctr) {
847 | return compose(sequenceA(point), map(f))(fctr);
848 | });
849 |
850 | var foldMap = curry(function(f, fldable) {
851 | return fldable.reduce(function(acc, x) {
852 | var r = f(x);
853 | acc = acc || r.empty();
854 | return acc.concat(r);
855 | }, null);
856 | });
857 |
858 | var fold = foldMap(I);
859 |
860 | var toList = function(x) {
861 | return x.reduce(function(acc, y) {
862 | return [y].concat(acc);
863 | }, []);
864 | };
865 |
866 | var expose = function(env) {
867 | var f;
868 | for (f in pointy) {
869 | if (f !== 'expose' && pointy.hasOwnProperty(f)) {
870 | env[f] = pointy[f];
871 | }
872 | }
873 | }
874 |
875 | pointy.I = id;
876 | pointy.K = K;
877 | pointy.compose = compose;
878 | pointy.curry = curry; //lodash curry
879 | pointy.of = of;
880 | pointy.map = map;
881 | pointy.ap = ap;
882 | pointy.liftA2 = liftA2;
883 | pointy.liftA3 = liftA3;
884 | pointy.chain = chain;
885 | pointy.mjoin = mjoin;
886 | pointy.concat = concat;
887 | pointy.mappend = concat;
888 | pointy.mconcat = mconcat;
889 | pointy.sequenceA = sequenceA;
890 | pointy.traverse = traverse;
891 | pointy.foldMap = foldMap;
892 | pointy.fold = fold;
893 | pointy.toList = toList;
894 | pointy.expose = expose;
895 |
896 | module.exports = pointy;
897 |
898 | if(typeof window == "object") {
899 | pointfree = pointy;
900 | }
901 |
902 | },{"./instances/array":1,"./instances/function":2,"./instances/string":3,"lodash.curry":4}]},{},[26])
903 | return pointfree
904 | });
--------------------------------------------------------------------------------
/dist/pointfree.browser.js:
--------------------------------------------------------------------------------
1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o
166 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
167 | * Copyright 2012-2013 The Dojo Foundation
168 | * Based on Underscore.js 1.5.2
169 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
170 | * Available under MIT license
171 | */
172 | var createWrapper = require('lodash._createwrapper');
173 |
174 | /**
175 | * Creates a function which accepts one or more arguments of `func` that when
176 | * invoked either executes `func` returning its result, if all `func` arguments
177 | * have been provided, or returns a function that accepts one or more of the
178 | * remaining `func` arguments, and so on. The arity of `func` can be specified
179 | * if `func.length` is not sufficient.
180 | *
181 | * @static
182 | * @memberOf _
183 | * @category Functions
184 | * @param {Function} func The function to curry.
185 | * @param {number} [arity=func.length] The arity of `func`.
186 | * @returns {Function} Returns the new curried function.
187 | * @example
188 | *
189 | * var curried = _.curry(function(a, b, c) {
190 | * console.log(a + b + c);
191 | * });
192 | *
193 | * curried(1)(2)(3);
194 | * // => 6
195 | *
196 | * curried(1, 2)(3);
197 | * // => 6
198 | *
199 | * curried(1, 2, 3);
200 | * // => 6
201 | */
202 | function curry(func, arity) {
203 | arity = typeof arity == 'number' ? arity : (+arity || func.length);
204 | return createWrapper(func, 4, null, null, null, arity);
205 | }
206 |
207 | module.exports = curry;
208 |
209 | },{"lodash._createwrapper":5}],5:[function(require,module,exports){
210 | /**
211 | * Lo-Dash 2.4.1 (Custom Build)
212 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
213 | * Copyright 2012-2013 The Dojo Foundation
214 | * Based on Underscore.js 1.5.2
215 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
216 | * Available under MIT license
217 | */
218 | var baseBind = require('lodash._basebind'),
219 | baseCreateWrapper = require('lodash._basecreatewrapper'),
220 | isFunction = require('lodash.isfunction'),
221 | slice = require('lodash._slice');
222 |
223 | /**
224 | * Used for `Array` method references.
225 | *
226 | * Normally `Array.prototype` would suffice, however, using an array literal
227 | * avoids issues in Narwhal.
228 | */
229 | var arrayRef = [];
230 |
231 | /** Native method shortcuts */
232 | var push = arrayRef.push,
233 | unshift = arrayRef.unshift;
234 |
235 | /**
236 | * Creates a function that, when called, either curries or invokes `func`
237 | * with an optional `this` binding and partially applied arguments.
238 | *
239 | * @private
240 | * @param {Function|string} func The function or method name to reference.
241 | * @param {number} bitmask The bitmask of method flags to compose.
242 | * The bitmask may be composed of the following flags:
243 | * 1 - `_.bind`
244 | * 2 - `_.bindKey`
245 | * 4 - `_.curry`
246 | * 8 - `_.curry` (bound)
247 | * 16 - `_.partial`
248 | * 32 - `_.partialRight`
249 | * @param {Array} [partialArgs] An array of arguments to prepend to those
250 | * provided to the new function.
251 | * @param {Array} [partialRightArgs] An array of arguments to append to those
252 | * provided to the new function.
253 | * @param {*} [thisArg] The `this` binding of `func`.
254 | * @param {number} [arity] The arity of `func`.
255 | * @returns {Function} Returns the new function.
256 | */
257 | function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
258 | var isBind = bitmask & 1,
259 | isBindKey = bitmask & 2,
260 | isCurry = bitmask & 4,
261 | isCurryBound = bitmask & 8,
262 | isPartial = bitmask & 16,
263 | isPartialRight = bitmask & 32;
264 |
265 | if (!isBindKey && !isFunction(func)) {
266 | throw new TypeError;
267 | }
268 | if (isPartial && !partialArgs.length) {
269 | bitmask &= ~16;
270 | isPartial = partialArgs = false;
271 | }
272 | if (isPartialRight && !partialRightArgs.length) {
273 | bitmask &= ~32;
274 | isPartialRight = partialRightArgs = false;
275 | }
276 | var bindData = func && func.__bindData__;
277 | if (bindData && bindData !== true) {
278 | // clone `bindData`
279 | bindData = slice(bindData);
280 | if (bindData[2]) {
281 | bindData[2] = slice(bindData[2]);
282 | }
283 | if (bindData[3]) {
284 | bindData[3] = slice(bindData[3]);
285 | }
286 | // set `thisBinding` is not previously bound
287 | if (isBind && !(bindData[1] & 1)) {
288 | bindData[4] = thisArg;
289 | }
290 | // set if previously bound but not currently (subsequent curried functions)
291 | if (!isBind && bindData[1] & 1) {
292 | bitmask |= 8;
293 | }
294 | // set curried arity if not yet set
295 | if (isCurry && !(bindData[1] & 4)) {
296 | bindData[5] = arity;
297 | }
298 | // append partial left arguments
299 | if (isPartial) {
300 | push.apply(bindData[2] || (bindData[2] = []), partialArgs);
301 | }
302 | // append partial right arguments
303 | if (isPartialRight) {
304 | unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
305 | }
306 | // merge flags
307 | bindData[1] |= bitmask;
308 | return createWrapper.apply(null, bindData);
309 | }
310 | // fast path for `_.bind`
311 | var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
312 | return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
313 | }
314 |
315 | module.exports = createWrapper;
316 |
317 | },{"lodash._basebind":6,"lodash._basecreatewrapper":15,"lodash._slice":24,"lodash.isfunction":25}],6:[function(require,module,exports){
318 | /**
319 | * Lo-Dash 2.4.1 (Custom Build)
320 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
321 | * Copyright 2012-2013 The Dojo Foundation
322 | * Based on Underscore.js 1.5.2
323 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
324 | * Available under MIT license
325 | */
326 | var baseCreate = require('lodash._basecreate'),
327 | isObject = require('lodash.isobject'),
328 | setBindData = require('lodash._setbinddata'),
329 | slice = require('lodash._slice');
330 |
331 | /**
332 | * Used for `Array` method references.
333 | *
334 | * Normally `Array.prototype` would suffice, however, using an array literal
335 | * avoids issues in Narwhal.
336 | */
337 | var arrayRef = [];
338 |
339 | /** Native method shortcuts */
340 | var push = arrayRef.push;
341 |
342 | /**
343 | * The base implementation of `_.bind` that creates the bound function and
344 | * sets its meta data.
345 | *
346 | * @private
347 | * @param {Array} bindData The bind data array.
348 | * @returns {Function} Returns the new bound function.
349 | */
350 | function baseBind(bindData) {
351 | var func = bindData[0],
352 | partialArgs = bindData[2],
353 | thisArg = bindData[4];
354 |
355 | function bound() {
356 | // `Function#bind` spec
357 | // http://es5.github.io/#x15.3.4.5
358 | if (partialArgs) {
359 | // avoid `arguments` object deoptimizations by using `slice` instead
360 | // of `Array.prototype.slice.call` and not assigning `arguments` to a
361 | // variable as a ternary expression
362 | var args = slice(partialArgs);
363 | push.apply(args, arguments);
364 | }
365 | // mimic the constructor's `return` behavior
366 | // http://es5.github.io/#x13.2.2
367 | if (this instanceof bound) {
368 | // ensure `new bound` is an instance of `func`
369 | var thisBinding = baseCreate(func.prototype),
370 | result = func.apply(thisBinding, args || arguments);
371 | return isObject(result) ? result : thisBinding;
372 | }
373 | return func.apply(thisArg, args || arguments);
374 | }
375 | setBindData(bound, bindData);
376 | return bound;
377 | }
378 |
379 | module.exports = baseBind;
380 |
381 | },{"lodash._basecreate":7,"lodash._setbinddata":10,"lodash._slice":24,"lodash.isobject":13}],7:[function(require,module,exports){
382 | var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/**
383 | * Lo-Dash 2.4.1 (Custom Build)
384 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
385 | * Copyright 2012-2013 The Dojo Foundation
386 | * Based on Underscore.js 1.5.2
387 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
388 | * Available under MIT license
389 | */
390 | var isNative = require('lodash._isnative'),
391 | isObject = require('lodash.isobject'),
392 | noop = require('lodash.noop');
393 |
394 | /* Native method shortcuts for methods with the same name as other `lodash` methods */
395 | var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate;
396 |
397 | /**
398 | * The base implementation of `_.create` without support for assigning
399 | * properties to the created object.
400 | *
401 | * @private
402 | * @param {Object} prototype The object to inherit from.
403 | * @returns {Object} Returns the new object.
404 | */
405 | function baseCreate(prototype, properties) {
406 | return isObject(prototype) ? nativeCreate(prototype) : {};
407 | }
408 | // fallback for browsers without `Object.create`
409 | if (!nativeCreate) {
410 | baseCreate = (function() {
411 | function Object() {}
412 | return function(prototype) {
413 | if (isObject(prototype)) {
414 | Object.prototype = prototype;
415 | var result = new Object;
416 | Object.prototype = null;
417 | }
418 | return result || global.Object();
419 | };
420 | }());
421 | }
422 |
423 | module.exports = baseCreate;
424 |
425 | },{"lodash._isnative":8,"lodash.isobject":13,"lodash.noop":9}],8:[function(require,module,exports){
426 | /**
427 | * Lo-Dash 2.4.1 (Custom Build)
428 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
429 | * Copyright 2012-2013 The Dojo Foundation
430 | * Based on Underscore.js 1.5.2
431 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
432 | * Available under MIT license
433 | */
434 |
435 | /** Used for native method references */
436 | var objectProto = Object.prototype;
437 |
438 | /** Used to resolve the internal [[Class]] of values */
439 | var toString = objectProto.toString;
440 |
441 | /** Used to detect if a method is native */
442 | var reNative = RegExp('^' +
443 | String(toString)
444 | .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
445 | .replace(/toString| for [^\]]+/g, '.*?') + '$'
446 | );
447 |
448 | /**
449 | * Checks if `value` is a native function.
450 | *
451 | * @private
452 | * @param {*} value The value to check.
453 | * @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
454 | */
455 | function isNative(value) {
456 | return typeof value == 'function' && reNative.test(value);
457 | }
458 |
459 | module.exports = isNative;
460 |
461 | },{}],9:[function(require,module,exports){
462 | /**
463 | * Lo-Dash 2.4.1 (Custom Build)
464 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
465 | * Copyright 2012-2013 The Dojo Foundation
466 | * Based on Underscore.js 1.5.2
467 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
468 | * Available under MIT license
469 | */
470 |
471 | /**
472 | * A no-operation function.
473 | *
474 | * @static
475 | * @memberOf _
476 | * @category Utilities
477 | * @example
478 | *
479 | * var object = { 'name': 'fred' };
480 | * _.noop(object) === undefined;
481 | * // => true
482 | */
483 | function noop() {
484 | // no operation performed
485 | }
486 |
487 | module.exports = noop;
488 |
489 | },{}],10:[function(require,module,exports){
490 | /**
491 | * Lo-Dash 2.4.1 (Custom Build)
492 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
493 | * Copyright 2012-2013 The Dojo Foundation
494 | * Based on Underscore.js 1.5.2
495 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
496 | * Available under MIT license
497 | */
498 | var isNative = require('lodash._isnative'),
499 | noop = require('lodash.noop');
500 |
501 | /** Used as the property descriptor for `__bindData__` */
502 | var descriptor = {
503 | 'configurable': false,
504 | 'enumerable': false,
505 | 'value': null,
506 | 'writable': false
507 | };
508 |
509 | /** Used to set meta data on functions */
510 | var defineProperty = (function() {
511 | // IE 8 only accepts DOM elements
512 | try {
513 | var o = {},
514 | func = isNative(func = Object.defineProperty) && func,
515 | result = func(o, o, o) && func;
516 | } catch(e) { }
517 | return result;
518 | }());
519 |
520 | /**
521 | * Sets `this` binding data on a given function.
522 | *
523 | * @private
524 | * @param {Function} func The function to set data on.
525 | * @param {Array} value The data array to set.
526 | */
527 | var setBindData = !defineProperty ? noop : function(func, value) {
528 | descriptor.value = value;
529 | defineProperty(func, '__bindData__', descriptor);
530 | };
531 |
532 | module.exports = setBindData;
533 |
534 | },{"lodash._isnative":11,"lodash.noop":12}],11:[function(require,module,exports){
535 | module.exports=require(8)
536 | },{}],12:[function(require,module,exports){
537 | module.exports=require(9)
538 | },{}],13:[function(require,module,exports){
539 | /**
540 | * Lo-Dash 2.4.1 (Custom Build)
541 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
542 | * Copyright 2012-2013 The Dojo Foundation
543 | * Based on Underscore.js 1.5.2
544 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
545 | * Available under MIT license
546 | */
547 | var objectTypes = require('lodash._objecttypes');
548 |
549 | /**
550 | * Checks if `value` is the language type of Object.
551 | * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
552 | *
553 | * @static
554 | * @memberOf _
555 | * @category Objects
556 | * @param {*} value The value to check.
557 | * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
558 | * @example
559 | *
560 | * _.isObject({});
561 | * // => true
562 | *
563 | * _.isObject([1, 2, 3]);
564 | * // => true
565 | *
566 | * _.isObject(1);
567 | * // => false
568 | */
569 | function isObject(value) {
570 | // check if the value is the ECMAScript language type of Object
571 | // http://es5.github.io/#x8
572 | // and avoid a V8 bug
573 | // http://code.google.com/p/v8/issues/detail?id=2291
574 | return !!(value && objectTypes[typeof value]);
575 | }
576 |
577 | module.exports = isObject;
578 |
579 | },{"lodash._objecttypes":14}],14:[function(require,module,exports){
580 | /**
581 | * Lo-Dash 2.4.1 (Custom Build)
582 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
583 | * Copyright 2012-2013 The Dojo Foundation
584 | * Based on Underscore.js 1.5.2
585 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
586 | * Available under MIT license
587 | */
588 |
589 | /** Used to determine if values are of the language type Object */
590 | var objectTypes = {
591 | 'boolean': false,
592 | 'function': true,
593 | 'object': true,
594 | 'number': false,
595 | 'string': false,
596 | 'undefined': false
597 | };
598 |
599 | module.exports = objectTypes;
600 |
601 | },{}],15:[function(require,module,exports){
602 | /**
603 | * Lo-Dash 2.4.1 (Custom Build)
604 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
605 | * Copyright 2012-2013 The Dojo Foundation
606 | * Based on Underscore.js 1.5.2
607 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
608 | * Available under MIT license
609 | */
610 | var baseCreate = require('lodash._basecreate'),
611 | isObject = require('lodash.isobject'),
612 | setBindData = require('lodash._setbinddata'),
613 | slice = require('lodash._slice');
614 |
615 | /**
616 | * Used for `Array` method references.
617 | *
618 | * Normally `Array.prototype` would suffice, however, using an array literal
619 | * avoids issues in Narwhal.
620 | */
621 | var arrayRef = [];
622 |
623 | /** Native method shortcuts */
624 | var push = arrayRef.push;
625 |
626 | /**
627 | * The base implementation of `createWrapper` that creates the wrapper and
628 | * sets its meta data.
629 | *
630 | * @private
631 | * @param {Array} bindData The bind data array.
632 | * @returns {Function} Returns the new function.
633 | */
634 | function baseCreateWrapper(bindData) {
635 | var func = bindData[0],
636 | bitmask = bindData[1],
637 | partialArgs = bindData[2],
638 | partialRightArgs = bindData[3],
639 | thisArg = bindData[4],
640 | arity = bindData[5];
641 |
642 | var isBind = bitmask & 1,
643 | isBindKey = bitmask & 2,
644 | isCurry = bitmask & 4,
645 | isCurryBound = bitmask & 8,
646 | key = func;
647 |
648 | function bound() {
649 | var thisBinding = isBind ? thisArg : this;
650 | if (partialArgs) {
651 | var args = slice(partialArgs);
652 | push.apply(args, arguments);
653 | }
654 | if (partialRightArgs || isCurry) {
655 | args || (args = slice(arguments));
656 | if (partialRightArgs) {
657 | push.apply(args, partialRightArgs);
658 | }
659 | if (isCurry && args.length < arity) {
660 | bitmask |= 16 & ~32;
661 | return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
662 | }
663 | }
664 | args || (args = arguments);
665 | if (isBindKey) {
666 | func = thisBinding[key];
667 | }
668 | if (this instanceof bound) {
669 | thisBinding = baseCreate(func.prototype);
670 | var result = func.apply(thisBinding, args);
671 | return isObject(result) ? result : thisBinding;
672 | }
673 | return func.apply(thisBinding, args);
674 | }
675 | setBindData(bound, bindData);
676 | return bound;
677 | }
678 |
679 | module.exports = baseCreateWrapper;
680 |
681 | },{"lodash._basecreate":16,"lodash._setbinddata":19,"lodash._slice":24,"lodash.isobject":22}],16:[function(require,module,exports){
682 | arguments[4][7][0].apply(exports,arguments)
683 | },{"lodash._isnative":17,"lodash.isobject":22,"lodash.noop":18}],17:[function(require,module,exports){
684 | module.exports=require(8)
685 | },{}],18:[function(require,module,exports){
686 | module.exports=require(9)
687 | },{}],19:[function(require,module,exports){
688 | module.exports=require(10)
689 | },{"lodash._isnative":20,"lodash.noop":21}],20:[function(require,module,exports){
690 | module.exports=require(8)
691 | },{}],21:[function(require,module,exports){
692 | module.exports=require(9)
693 | },{}],22:[function(require,module,exports){
694 | module.exports=require(13)
695 | },{"lodash._objecttypes":23}],23:[function(require,module,exports){
696 | module.exports=require(14)
697 | },{}],24:[function(require,module,exports){
698 | /**
699 | * Lo-Dash 2.4.1 (Custom Build)
700 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
701 | * Copyright 2012-2013 The Dojo Foundation
702 | * Based on Underscore.js 1.5.2
703 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
704 | * Available under MIT license
705 | */
706 |
707 | /**
708 | * Slices the `collection` from the `start` index up to, but not including,
709 | * the `end` index.
710 | *
711 | * Note: This function is used instead of `Array#slice` to support node lists
712 | * in IE < 9 and to ensure dense arrays are returned.
713 | *
714 | * @private
715 | * @param {Array|Object|string} collection The collection to slice.
716 | * @param {number} start The start index.
717 | * @param {number} end The end index.
718 | * @returns {Array} Returns the new array.
719 | */
720 | function slice(array, start, end) {
721 | start || (start = 0);
722 | if (typeof end == 'undefined') {
723 | end = array ? array.length : 0;
724 | }
725 | var index = -1,
726 | length = end - start || 0,
727 | result = Array(length < 0 ? 0 : length);
728 |
729 | while (++index < length) {
730 | result[index] = array[start + index];
731 | }
732 | return result;
733 | }
734 |
735 | module.exports = slice;
736 |
737 | },{}],25:[function(require,module,exports){
738 | /**
739 | * Lo-Dash 2.4.1 (Custom Build)
740 | * Build: `lodash modularize modern exports="npm" -o ./npm/`
741 | * Copyright 2012-2013 The Dojo Foundation
742 | * Based on Underscore.js 1.5.2
743 | * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
744 | * Available under MIT license
745 | */
746 |
747 | /**
748 | * Checks if `value` is a function.
749 | *
750 | * @static
751 | * @memberOf _
752 | * @category Objects
753 | * @param {*} value The value to check.
754 | * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
755 | * @example
756 | *
757 | * _.isFunction(_);
758 | * // => true
759 | */
760 | function isFunction(value) {
761 | return typeof value == 'function';
762 | }
763 |
764 | module.exports = isFunction;
765 |
766 | },{}],26:[function(require,module,exports){
767 | var curry = require('lodash.curry');
768 |
769 | var BUILT_INS = { 'array': require('./instances/array')
770 | , 'function': require('./instances/function')
771 | , 'string': require('./instances/string')
772 | }
773 |
774 | var _groupsOf = curry(function(n, xs) {
775 | if(!xs.length) return [];
776 | return [xs.slice(0, n)].concat(_groupsOf(n, xs.slice(n, xs.length)));
777 | });
778 |
779 | var _compose = curry(function(f,g,x) { return f(g(x)) });
780 |
781 | var I = function(x){ return x; }
782 |
783 | // f . g . h == compose(f, g, h)
784 | var toAssociativeCommaInfix = function(fn) {
785 | return function() {
786 | var fns = [].slice.call(arguments)
787 | return function() {
788 | return _groupsOf(2, fns).reverse().map(function(g) {
789 | return (g.length > 1) ? fn.apply(this,g) : g[0];
790 | }).reduce(function(x, f) {
791 | return [f.apply(f,x)];
792 | }, arguments)[0];
793 | };
794 | };
795 | };
796 |
797 | var compose = toAssociativeCommaInfix(_compose);
798 |
799 |
800 | var pointy = {};
801 |
802 | var id = function(x) { return x; }
803 | var K = function(x) { return function(){ return x; } }
804 |
805 | var map = curry(function(f, u) {
806 | return u.fmap ? u.fmap(f) : u.map(f); //sometimes map passes index so we use fmap if it has it.
807 | });
808 |
809 | var ap = curry(function(a1, a2) {
810 | return a1.ap(a2);
811 | });
812 |
813 | var liftA2 = curry(function(f, x, y) {
814 | return map(f,x).ap(y);
815 | });
816 |
817 | var liftA3 = curry(function(f, x, y, z) {
818 | return map(f, x).ap(y).ap(z);
819 | });
820 |
821 | var chain = curry(function(f, mv) {
822 | return mv.chain(f);
823 | });
824 |
825 | var mjoin = function(mmv) {
826 | return chain(id, mmv);
827 | };
828 |
829 | var concat = curry(function(x, y) {
830 | return x.concat(y);
831 | });
832 |
833 | var mconcat = function(xs, empty) {
834 | return xs.length ? xs.reduce(concat) : empty();
835 | };
836 |
837 | var sequenceA = curry(function(point, fctr) {
838 | return fctr.traverse(id, point);
839 | });
840 |
841 | var of = function(x) {
842 | return x.of;
843 | };
844 |
845 | var traverse = curry(function(f, point, fctr) {
846 | return compose(sequenceA(point), map(f))(fctr);
847 | });
848 |
849 | var foldMap = curry(function(f, fldable) {
850 | return fldable.reduce(function(acc, x) {
851 | var r = f(x);
852 | acc = acc || r.empty();
853 | return acc.concat(r);
854 | }, null);
855 | });
856 |
857 | var fold = foldMap(I);
858 |
859 | var toList = function(x) {
860 | return x.reduce(function(acc, y) {
861 | return [y].concat(acc);
862 | }, []);
863 | };
864 |
865 | var expose = function(env) {
866 | var f;
867 | for (f in pointy) {
868 | if (f !== 'expose' && pointy.hasOwnProperty(f)) {
869 | env[f] = pointy[f];
870 | }
871 | }
872 | }
873 |
874 | pointy.I = id;
875 | pointy.K = K;
876 | pointy.compose = compose;
877 | pointy.curry = curry; //lodash curry
878 | pointy.of = of;
879 | pointy.map = map;
880 | pointy.ap = ap;
881 | pointy.liftA2 = liftA2;
882 | pointy.liftA3 = liftA3;
883 | pointy.chain = chain;
884 | pointy.mjoin = mjoin;
885 | pointy.concat = concat;
886 | pointy.mappend = concat;
887 | pointy.mconcat = mconcat;
888 | pointy.sequenceA = sequenceA;
889 | pointy.traverse = traverse;
890 | pointy.foldMap = foldMap;
891 | pointy.fold = fold;
892 | pointy.toList = toList;
893 | pointy.expose = expose;
894 |
895 | module.exports = pointy;
896 |
897 | if(typeof window == "object") {
898 | pointfree = pointy;
899 | }
900 |
901 | },{"./instances/array":1,"./instances/function":2,"./instances/string":3,"lodash.curry":4}]},{},[26])
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./pointfree');
--------------------------------------------------------------------------------
/instances/array.js:
--------------------------------------------------------------------------------
1 | var curry = require('lodash.curry');
2 |
3 | var _flatten = function(xs) {
4 | return xs.reduce(function(a,b){return a.concat(b);}, []);
5 | };
6 |
7 | var _fmap = function(f) {
8 | var xs = this;
9 | return xs.map(function(x) { return f(x); }); //avoid index
10 | };
11 |
12 | Object.defineProperty(Array.prototype, 'fmap',{
13 | value: _fmap,
14 | writable: true,
15 | configurable: true,
16 | enumerable: false
17 | });
18 |
19 | var _empty = function() { return []; };
20 |
21 | Object.defineProperty(Array.prototype, 'empty',{
22 | value: _empty,
23 | writable: true,
24 | configurable: true,
25 | enumerable: false
26 | });
27 |
28 | var _chain = function(f) { return _flatten(this.fmap(f)); };
29 |
30 | Object.defineProperty(Array.prototype, 'chain',{
31 | value: _chain,
32 | writable: true,
33 | configurable: true,
34 | enumerable: false
35 | });
36 |
37 | var _of = function(x) { return [x]; };
38 |
39 | Object.defineProperty(Array.prototype, 'of',{
40 | value: _of,
41 | writable: true,
42 | configurable: true,
43 | enumerable: false
44 | });
45 |
46 | var _ap = function(a2) {
47 | var a1 = this;
48 | return _flatten(a1.map(function(f){
49 | return a2.map(function(a){ return f(a); })
50 | }));
51 | };
52 |
53 | Object.defineProperty(Array.prototype, 'ap',{
54 | value: _ap,
55 | writable: true,
56 | configurable: true,
57 | enumerable: false
58 | });
59 |
60 | var _traverse = function(f, point) {
61 | var cons_f = function(ys, x){
62 | return f(x).map(function(x){ return function(y){ return y.concat(x); } }).ap(ys);
63 | }
64 | return this.reduce(cons_f, point([]));
65 | };
66 |
67 | Object.defineProperty(Array.prototype, 'traverse',{
68 | value: _traverse,
69 | writable: true,
70 | configurable: true,
71 | enumerable: false
72 | });
73 |
74 |
--------------------------------------------------------------------------------
/instances/const.js:
--------------------------------------------------------------------------------
1 | var ConstType = function(val) {
2 | this.val = val;
3 | }
4 |
5 | var getConst = function(c) { return c.val; };
6 |
7 | var Const = function(val) {
8 | return new ConstType(val);
9 | };
10 |
11 |
12 | ConstType.prototype.map = function(f) {
13 | return Const(this.val);
14 | };
15 |
16 | // is const an applicative?
17 | // only if x is a monoid
18 | ConstType.prototype.of = function(x) {
19 | return Const(x.empty());
20 | };
21 |
22 | ConstType.prototype.ap = function(c2) {
23 | return Const(this.val.concat(c2.val));
24 | };
25 |
26 | Const.of = ConstType.prototype.of;
27 |
28 | // const is not a monad
29 |
30 | module.exports = {Const: Const, getConst: getConst}
31 |
--------------------------------------------------------------------------------
/instances/function.js:
--------------------------------------------------------------------------------
1 | var _K = function(x) { return function(y) { return x; } };
2 |
3 | var _map = function(g) {
4 | var f = this;
5 | return function(x) { return g(f(x)) };
6 | };
7 |
8 | Object.defineProperty(Function.prototype, 'map',{
9 | value: _map,
10 | writable: true,
11 | configurable: true,
12 | enumerable: false
13 | });
14 |
15 | var _concat = function(g) {
16 | var f = this;
17 | return function() {
18 | return f.apply(this, arguments).concat(g.apply(this, arguments))
19 | }
20 | };
21 |
22 | Object.defineProperty(Function.prototype, 'concat',{
23 | value: _concat,
24 | writable: true,
25 | configurable: true,
26 | enumerable: false
27 | });
28 |
29 | var _empty = function() {
30 | return _K({ concat: function(g) { return g.empty().concat(g); } });
31 | };
32 |
33 | Object.defineProperty(Function.prototype, 'empty',{
34 | value: _empty,
35 | writable: true,
36 | configurable: true,
37 | enumerable: false
38 | });
39 |
40 | var _chain = function(g) {
41 | var f = this;
42 | return function(x) {
43 | return g(f(x), x);
44 | };
45 | };
46 |
47 | Object.defineProperty(Function.prototype, 'chain',{
48 | value: _chain,
49 | writable: true,
50 | configurable: true,
51 | enumerable: false
52 | });
53 |
54 | var _of = _K;
55 |
56 | Object.defineProperty(Function.prototype, 'of',{
57 | value: _of,
58 | writable: true,
59 | configurable: true,
60 | enumerable: false
61 | });
62 |
63 | var _ap = function(g) {
64 | var f = this;
65 | return function(x) {
66 | return f(x)(g(x));
67 | }
68 | };
69 |
70 | Object.defineProperty(Function.prototype, 'ap',{
71 | value: _ap,
72 | writable: true,
73 | configurable: true,
74 | enumerable: false
75 | });
76 |
--------------------------------------------------------------------------------
/instances/identity.js:
--------------------------------------------------------------------------------
1 | var Constructor = require('../util').Constructor;
2 |
3 | var Id = Constructor(function(a) {
4 | this.value = a;
5 | });
6 |
7 | Id.prototype.concat = function(b) {
8 | return new Id(concat(this.value, b.value));
9 | };
10 |
11 | var runIdentity = function(i) { return i.value; };
12 |
13 | Id.prototype.empty = function() {
14 | return new Id(this.value.empty());
15 | };
16 |
17 | Id.prototype.map = function(f) {
18 | return new Id(f(this.value));
19 | };
20 |
21 | Id.prototype.ap = function(b) {
22 | return new Id(this.value(b.value));
23 | };
24 |
25 | Id.prototype.chain = function(f) {
26 | return f(this.value);
27 | };
28 |
29 | Id.prototype.of = function(a) {
30 | return new Id(a);
31 | };
32 |
33 | module.exports = {Identity: Id, runIdentity: runIdentity};
34 |
--------------------------------------------------------------------------------
/instances/maybe.js:
--------------------------------------------------------------------------------
1 | var util = require('../util')
2 | , makeType = util.makeType
3 | , subClass = util.subClass
4 | , map = require('../pointfree').map
5 | ;
6 |
7 | var MaybeType = makeType()
8 | , Just = subClass(MaybeType)
9 | , Nothing = subClass(MaybeType)
10 | ;
11 |
12 | //+ notThere :: a -> Bool
13 | var notThere = function(val) {
14 | return (val === undefined || val === null);
15 | }
16 |
17 | var Maybe = function(x) {
18 | return notThere(x) ? Nothing() : Just(x);
19 | };
20 |
21 | Maybe.Just = Just;
22 | Maybe.Nothing = Nothing;
23 |
24 | Nothing.prototype.concat = function(b) {
25 | return b;
26 | }
27 | Just.prototype.concat = function(b) {
28 | if(notThere(b.val)) return this;
29 | return Maybe(this.val.concat(b.val));
30 | };
31 |
32 | MaybeType.prototype.empty = function() { return Nothing(); }
33 |
34 | Nothing.prototype.map = function(f) {
35 | return Nothing();
36 | }
37 | Just.prototype.map = function(f) {
38 | return Just(f(this.val));
39 | }
40 | Maybe.of = Maybe;
41 | Nothing.prototype.of = function(x) { return Nothing(x) };
42 | Just.prototype.of = function(x) { return Just(x) };
43 |
44 | Nothing.prototype.ap = function(m) {
45 | return Nothing();
46 | }
47 | Just.prototype.ap = function(m) {
48 | return map(this.val, m);
49 | }
50 |
51 | Nothing.prototype.chain = function(f) {
52 | return this;
53 | }
54 | Just.prototype.chain = function(f) {
55 | return f(this.val);
56 | }
57 | Nothing.prototype.traverse = function(f, point) {
58 | return point(Nothing());
59 | }
60 | Just.prototype.traverse = function(f, point) {
61 | return f(this.val).map(Just);
62 | };
63 | Nothing.prototype.reduce = function(f) {
64 | return f(null);
65 | };
66 | Just.prototype.reduce = function(f, acc) {
67 | return f(acc, this.val);
68 | };
69 |
70 | module.exports = Maybe;
71 |
--------------------------------------------------------------------------------
/instances/monoids.js:
--------------------------------------------------------------------------------
1 | var Constructor = require('../util').Constructor;
2 |
3 | var inspect = function(x) {
4 | if(x==null || x==undefined) return "null";
5 | return x.inspect ? x.inspect() : x;
6 | }
7 |
8 | var getResult = function(x) { return x.val; };
9 |
10 | var Max = Constructor(function(val) {
11 | this.val = val;
12 | });
13 |
14 | Max.prototype.empty = function() { return Max(Number.MIN_VALUE); };
15 |
16 | Max.prototype.concat = function(s2) { return Max(this.val > s2.val ? this.val : s2.val); };
17 |
18 | Max.prototype.inspect = function(f) {
19 | return 'Max('+inspect(this.val)+')';
20 | };
21 |
22 | var Min = Constructor(function(val) {
23 | this.val = val;
24 | });
25 |
26 |
27 | Min.prototype.empty = function() { return Min(Number.MAX_VALUE); };
28 |
29 | Min.prototype.concat = function(s2) { return Min(this.val < s2.val ? this.val : s2.val); };
30 |
31 | Min.prototype.inspect = function(f) {
32 | return 'Min('+inspect(this.val)+')';
33 | };
34 |
35 | var Sum = Constructor(function(val) {
36 | this.val = val;
37 | });
38 |
39 | Sum.prototype.empty = function() { return Sum(0); };
40 |
41 | Sum.prototype.concat = function(s2) { return Sum(this.val + s2.val); };
42 |
43 | Sum.prototype.inspect = function(f) {
44 | return 'Sum('+inspect(this.val)+')';
45 | };
46 |
47 |
48 | var Product = Constructor(function(val) {
49 | this.val = val;
50 | });
51 |
52 | Product.prototype.empty = function() { return Product(1); };
53 |
54 | Product.prototype.concat = function(s2) { return Product(this.val * s2.val); };
55 |
56 | Product.prototype.inspect = function(f) {
57 | return 'Product('+inspect(this.val)+')';
58 | };
59 |
60 |
61 | var Any = Constructor(function(val) {
62 | this.val = val;
63 | });
64 |
65 | Any.prototype.empty = function() { return Any(false); };
66 |
67 | Any.prototype.concat = function(s2) { return Any(this.val || s2.val); };
68 |
69 | Any.prototype.inspect = function(f) {
70 | return 'Any('+inspect(this.val)+')';
71 | };
72 |
73 |
74 | var All = Constructor(function(val) {
75 | this.val = val;
76 | });
77 |
78 | All.prototype.empty = function() { return All(true); };
79 |
80 | All.prototype.concat = function(s2) { return All(this.val && s2.val); };
81 |
82 | All.prototype.inspect = function(f) {
83 | return 'All('+inspect(this.val)+')';
84 | };
85 |
86 |
87 | module.exports = {Max: Max, Min: Min, Sum: Sum, Product: Product, Any: Any, All: All, getResult: getResult}
88 |
--------------------------------------------------------------------------------
/instances/string.js:
--------------------------------------------------------------------------------
1 | var _empty = function() { return ""; };
2 |
3 | Object.defineProperty(String.prototype, 'empty',{
4 | value: _empty,
5 | writable: true,
6 | configurable: true,
7 | enumerable: false
8 | });
9 |
--------------------------------------------------------------------------------
/instances/sum.js:
--------------------------------------------------------------------------------
1 | var Constructor = require('../util').Constructor;
2 |
3 | var Sum = Constructor(function(val) {
4 | this.val = val;
5 | });
6 |
7 | var getSum = function(c) { return c.val; };
8 |
9 | Sum.prototype.map = function(f) {
10 | return Sum(f(this.val));
11 | };
12 |
13 | Sum.prototype.empty = function() { return Sum(0); };
14 |
15 | Sum.prototype.concat = function(s2) { return Sum(this.val + s2.val); };
16 |
17 | Sum.prototype.of = function(x) {
18 | return Sum(x);
19 | };
20 |
21 | Sum.prototype.ap = function(s2) {
22 | return Sum(ap(this.val, s2.val));
23 | };
24 |
25 | Sum.prototype.chaim = function(f) {
26 | return f(this.val);
27 | };
28 |
29 | module.exports = {Sum: Sum, getSum: getSum}
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pointfree-fantasy",
3 | "version": "0.1.3",
4 | "description": "Point free wrappers for fantasy land js.",
5 | "main": "pointfree.js",
6 | "scripts": {
7 | "test": "mocha test"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/DrBoolean/pointfree-fantasy.git"
12 | },
13 | "keywords": [
14 | "functional",
15 | "fantasy",
16 | "pointfree",
17 | "tacit"
18 | ],
19 | "author": "Loop/Recur",
20 | "license": "MIT",
21 | "dependencies": {
22 | "lodash.curry": "*"
23 | },
24 | "devDependencies": {
25 | "mocha": "~1.9.0",
26 | "claire": "~0.4.1"
27 | },
28 | "bugs": {
29 | "url": "https://github.com/DrBoolean/pointfree-fantasy/issues"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/pointfree.js:
--------------------------------------------------------------------------------
1 | var curry = require('lodash.curry');
2 |
3 | var BUILT_INS = { 'array': require('./instances/array')
4 | , 'function': require('./instances/function')
5 | , 'string': require('./instances/string')
6 | }
7 |
8 | var _groupsOf = curry(function(n, xs) {
9 | if(!xs.length) return [];
10 | return [xs.slice(0, n)].concat(_groupsOf(n, xs.slice(n, xs.length)));
11 | });
12 |
13 | var _compose = curry(function(f,g,x) { return f(g(x)) });
14 |
15 | var I = function(x){ return x; }
16 |
17 | // f . g . h == compose(f, g, h)
18 | var toAssociativeCommaInfix = function(fn) {
19 | return function() {
20 | var fns = [].slice.call(arguments)
21 | return function() {
22 | return _groupsOf(2, fns).reverse().map(function(g) {
23 | return (g.length > 1) ? fn.apply(this,g) : g[0];
24 | }).reduce(function(x, f) {
25 | return [f.apply(f,x)];
26 | }, arguments)[0];
27 | };
28 | };
29 | };
30 |
31 | var compose = toAssociativeCommaInfix(_compose);
32 |
33 |
34 | var pointy = {};
35 |
36 | var id = function(x) { return x; }
37 | var K = function(x) { return function(){ return x; } }
38 |
39 | var map = curry(function(f, u) {
40 | if(u.fmap) return u.fmap(f); //sometimes map passes index so we use fmap if it has it.
41 | if(u.map) return u.map(f);
42 | return chain(compose(of(u), f), u);
43 | });
44 |
45 | var ap = curry(function(a1, a2) {
46 | if(a1.ap) return a1.ap(a2);
47 | return chain(map(curry.placeholder, a2), a1);
48 | });
49 |
50 | var liftA2 = curry(function(f, x, y) {
51 | return map(f,x).ap(y);
52 | });
53 |
54 | var liftA3 = curry(function(f, x, y, z) {
55 | return map(f, x).ap(y).ap(z);
56 | });
57 |
58 | var chain = curry(function(f, mv) {
59 | return mv.chain ? mv.chain(f) : mv.then(f);
60 | });
61 |
62 | var mjoin = function(mmv) {
63 | return chain(id, mmv);
64 | };
65 |
66 | var concat = curry(function(x, y) {
67 | return x.concat(y);
68 | });
69 |
70 | var mconcat = function(xs, empty) {
71 | return xs.length ? xs.reduce(concat) : empty();
72 | };
73 |
74 | var sequenceA = curry(function(point, fctr) {
75 | return fctr.traverse(id, point);
76 | });
77 |
78 | var of = function(x) {
79 | return x.of;
80 | };
81 |
82 | var traverse = curry(function(f, point, fctr) {
83 | return compose(sequenceA(point), map(f))(fctr);
84 | });
85 |
86 | var foldMap = curry(function(f, fldable) {
87 | return fldable.reduce(function(acc, x) {
88 | var r = f(x);
89 | acc = acc || r.empty();
90 | return acc.concat(r);
91 | }, null);
92 | });
93 |
94 | var fold = curry(function(f, g, x) { return x.fold(f, g) })
95 |
96 | var toList = function(x) {
97 | return x.reduce(function(acc, y) {
98 | return [y].concat(acc);
99 | }, []);
100 | };
101 |
102 | var expose = function(env) {
103 | var f;
104 | for (f in pointy) {
105 | if (f !== 'expose' && pointy.hasOwnProperty(f)) {
106 | env[f] = pointy[f];
107 | }
108 | }
109 | }
110 |
111 | pointy.I = id;
112 | pointy.K = K;
113 | pointy.compose = compose;
114 | pointy.curry = curry; //lodash curry
115 | pointy.of = of;
116 | pointy.map = map;
117 | pointy.ap = ap;
118 | pointy.liftA2 = liftA2;
119 | pointy.liftA3 = liftA3;
120 | pointy.chain = chain;
121 | pointy.mjoin = mjoin;
122 | pointy.concat = concat;
123 | pointy.mappend = concat;
124 | pointy.mconcat = mconcat;
125 | pointy.sequenceA = sequenceA;
126 | pointy.sequence = sequenceA;
127 | pointy.traverse = traverse;
128 | pointy.foldMap = foldMap;
129 | pointy.fold = fold;
130 | pointy.toList = toList;
131 | pointy.expose = expose;
132 |
133 | module.exports = pointy;
134 |
135 | if(typeof window == "object") {
136 | pointfree = pointy;
137 | }
138 |
--------------------------------------------------------------------------------
/test/array.js:
--------------------------------------------------------------------------------
1 | require('../pointfree').expose(global)
2 |
3 |
4 | var assert = require("assert")
5 | , quickCheckLaws = require('./helper').quickCheckLaws
6 | , curry = require('lodash.curry')
7 | , monoids = require('../instances/monoids')
8 | , claire = require('claire')
9 | , Maybe = require('../instances/maybe')
10 | , _ = claire.data
11 | , forAll = claire.forAll
12 | ;
13 |
14 | describe('Array', function(){
15 | quickCheckLaws({ 'Semigroup': _.Array(_.Int)
16 | , 'Monoid': _.Array(_.Int)
17 | , 'Functor': _.Array(_.Int)
18 | , 'Applicative': _.Array(_.Int)
19 | , 'Monad': _.Array(_.Int)
20 | });
21 |
22 | it('is traversable', function() {
23 | var f = function(x){ return Maybe(x); }
24 | var xs = [1,2];
25 | assert.deepEqual(traverse(f, Maybe.of, xs), Maybe([1,2]));
26 | })
27 |
28 | it('is foldable', function() {
29 | assert.deepEqual(foldMap(monoids.Sum, [1,2,3]), monoids.Sum(6))
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/test/const.js:
--------------------------------------------------------------------------------
1 | require('../pointfree').expose(global)
2 |
3 |
4 | var Constant = require('../instances/const')
5 | , quickCheckLaws = require('./helper').quickCheckLaws
6 | , Const = Constant.Const
7 | , getConst = Constant.getConst
8 | , assert = require("assert")
9 | , curry = require('lodash.curry')
10 | , claire = require('claire')
11 | , _ = claire.data
12 | , forAll = claire.forAll
13 | ;
14 |
15 | var ConstGen = claire.transform(Const, _.Str);
16 |
17 | describe('Const', function(){
18 | quickCheckLaws({ 'Functor': ConstGen });
19 |
20 | describe('Functor', function(){
21 | it('ignores map entirely', function(){
22 | var someFn = function(x) { return x + 'this will not happen'; };
23 | assert.deepEqual(map(someFn, Const('hi')), Const('hi'));
24 | });
25 | });
26 |
27 | describe('Applicative', function(){
28 | it('concats values if value is a monoid', function() {
29 | assert.deepEqual(Const('1').ap(Const('2')), Const('12'));
30 | });
31 | });
32 | });
33 |
34 |
35 |
--------------------------------------------------------------------------------
/test/function.js:
--------------------------------------------------------------------------------
1 | require('../pointfree').expose(global)
2 |
3 |
4 | var assert = require("assert")
5 | , quickCheckLaws = require('./helper').quickCheckLaws
6 | , curry = require('lodash.curry')
7 | , claire = require('claire')
8 | , _ = claire.data
9 | , asGenerator = claire.asGenerator
10 | , forAll = claire.forAll
11 | ;
12 |
13 | var _stubFn = function() { return function() { return _.Str.next().value }; };
14 | var FunGen = asGenerator(_stubFn)
15 |
16 |
17 | describe('Function', function(){
18 | var f = function(x) { return x + 'hello'}
19 | , g = function(y) { return y + 'world'}
20 | ;
21 |
22 | describe("Monoid", function() {
23 | it('runs the functions then concats the values together', function() {
24 | assert.equal(mappend(f, g)(' bla '), ' bla hello bla world')
25 | assert.equal(mconcat([f, g])(' bla '), ' bla hello bla world')
26 | });
27 | });
28 |
29 | describe("Functor", function() {
30 | it('composes the functions', function() {
31 | assert.equal(map(g, f)(' bla '), ' bla helloworld')
32 | });
33 | });
34 |
35 | describe("Applicative", function() {
36 | it('runs each function with the arg then passes the results on', function() {
37 | var h = curry(function(x,y) { return x.toUpperCase() + y.toLowerCase(); })
38 | assert.equal(liftA2(h, f, g)(' bla '), ' BLA HELLO bla world')
39 | });
40 |
41 | it('runs each function with the arg then passes the results on (with 3)', function() {
42 | var h = curry(function(x,y,z) { return x.toUpperCase() + y.toLowerCase() + z })
43 | var i = function(z) { return z + 'last'};
44 | assert.equal(liftA3(h, f, g, i)(' bla '), ' BLA HELLO bla world bla last')
45 | });
46 | });
47 | });
48 |
49 |
50 |
--------------------------------------------------------------------------------
/test/helper.js:
--------------------------------------------------------------------------------
1 | var assert = require("assert")
2 | , curry = require('lodash.curry')
3 | , claire = require('claire')
4 | , _ = claire.data
5 | , forAll = claire.forAll
6 | ;
7 |
8 | var add = curry(function(x, y) { return x + y; });
9 |
10 | var semigroupAssocTest = function(gen) {
11 | return forAll(gen, gen, gen).satisfy(function(a, b, c) {
12 | assert.deepEqual(mappend(mappend(a, b), c), mappend(a, mappend(b, c)));
13 | return true;
14 | }).asTest({times: 100});
15 | };
16 |
17 | var monoidIdentityTest = function(gen) {
18 | return forAll(gen).satisfy(function(m) {
19 | assert.deepEqual(mappend(m.empty(), m), mappend(m, m.empty()));
20 | return true;
21 | }).asTest({times: 100})
22 | };
23 |
24 | var functorIdentity = function(gen) {
25 | return forAll(gen).satisfy(function(m) {
26 | assert.deepEqual(map(I, m), I(m));
27 | return true;
28 | }).asTest({times: 100})
29 | };
30 |
31 | var functorComp = function(gen) {
32 | return forAll(gen).satisfy(function(m) {
33 | var f = add('one')
34 | , g = add('two');
35 | assert.deepEqual(map(compose(f, g), m), compose(map(f), map(g))(m));
36 | return true;
37 | }).asTest({times: 100})
38 | };
39 |
40 | var applicativeIdentity = function(gen) {
41 | return forAll(gen).satisfy(function(m) {
42 | assert.deepEqual(ap(m.of(I), m), m);
43 | return true;
44 | }).asTest({times: 100})
45 | };
46 |
47 | var applicativeComp = function(gen) {
48 | return forAll(gen, gen).satisfy(function(m, w) {
49 | var f = m.of(add('one'))
50 | , g = m.of(add('two'))
51 | , _compose = curry(function(f,g,x) { return f(g(x)); })
52 | ;
53 | assert.deepEqual(ap(ap(ap(m.of(_compose), f), g), w), ap(f, ap(g, w)));
54 | return true;
55 | }).asTest({times: 100})
56 | };
57 |
58 | var applicativeHomoMorph = function(gen) {
59 | return forAll(gen, _.Any).satisfy(function(m, x) {
60 | var f = function(y){ return [y]; }
61 | assert.deepEqual(ap(m.of(f), m.of(x)), m.of(f(x)));
62 | return true;
63 | }).asTest({times: 100})
64 | };
65 |
66 | var applicativeInterChange = function(gen) {
67 | return forAll(gen, _.Any).satisfy(function(m, x) {
68 | var u = m.of(function(x){ return [x]; });
69 | assert.deepEqual(ap(u, m.of(x)), ap(m.of(function(f) { return f(x); }), u));
70 | return true;
71 | }).asTest({times: 100});
72 | };
73 |
74 | var monadAssoc = function(gen) {
75 | return forAll(gen).satisfy(function(m) {
76 | var f = function(x){ return m.of(add('nest1', x))}
77 | , g = function(x){ return m.of(add('nest2', x))}
78 | , h = function(x){ return m.of(add('nest3', x))}
79 | , mcompose_ = curry(function(f, g, x) { return chain(f, g(x)); })
80 | ;
81 | assert.deepEqual(mcompose_(f, mcompose_(g, h))(m), mcompose_(mcompose_(f, g), h)(m));
82 | return true;
83 | }).asTest({times: 100});
84 | };
85 |
86 | var Laws = { 'Semigroup': [['associativity', semigroupAssocTest]]
87 | , 'Monoid': [['identity', monoidIdentityTest]]
88 | , 'Functor': [['identity', functorIdentity], ['composition', functorComp]]
89 | , 'Applicative': [ ['identity', applicativeIdentity]
90 | , ['composition', applicativeComp]
91 | , ['homomorphism', applicativeHomoMorph]
92 | , ['interchange', applicativeInterChange]
93 | ]
94 | , 'Monad': [['assoc', monadAssoc]]
95 | }
96 |
97 | module.exports.quickCheckLaws = function(laws) {
98 | Object.keys(laws).map(function(typeclass) {
99 | describe(typeclass, function() {
100 | Laws[typeclass].map(function(law) {
101 | it(law[0], law[1](laws[typeclass]));
102 | });
103 | });
104 | });
105 | };
106 |
--------------------------------------------------------------------------------
/test/identity.js:
--------------------------------------------------------------------------------
1 | require('../pointfree').expose(global)
2 |
3 |
4 | var assert = require("assert")
5 | , quickCheckLaws = require('./helper').quickCheckLaws
6 | , curry = require('lodash.curry')
7 | , claire = require('claire')
8 | , _ = claire.data
9 | , asGenerator = claire.asGenerator
10 | , forAll = claire.forAll
11 | , Identity = require('../instances/identity').Identity
12 | ;
13 |
14 | var IdentityGen = claire.transform(Identity, _.Str);
15 |
16 |
17 | describe('Identity', function(){
18 | quickCheckLaws({ 'Semigroup': IdentityGen
19 | , 'Monoid': IdentityGen
20 | , 'Functor': IdentityGen
21 | , 'Applicative': IdentityGen
22 | , 'Monad': IdentityGen
23 | });
24 | });
25 |
26 |
27 |
--------------------------------------------------------------------------------
/test/maybe.js:
--------------------------------------------------------------------------------
1 | require('../pointfree').expose(global)
2 |
3 | var Maybe = require('../instances/maybe')
4 | , Just = Maybe.Just
5 | , Nothing = Maybe.Nothing
6 | , assert = require("assert")
7 | , quickCheckLaws = require('./helper').quickCheckLaws
8 | , curry = require('lodash.curry')
9 | , claire = require('claire')
10 | , _ = claire.data
11 | , forAll = claire.forAll
12 | ;
13 |
14 | var pluck = curry(function(x, o) { return o[x]; });
15 |
16 | var safeGet = curry(function(x, o) { return Maybe(o[x]); });
17 |
18 | var add = curry(function(x, y) { return x + y; });
19 |
20 | var user = {email: "sally@test.com", address: {street: {number: 23, name: "Winston"}}}
21 |
22 | var MaybeGen = claire.transform(Maybe, _.Any);
23 | var MaybeMonoidGen = claire.transform(Maybe, _.Str);
24 |
25 | describe('Maybe', function(){
26 | quickCheckLaws({ 'Semigroup': MaybeMonoidGen
27 | , 'Monoid': MaybeMonoidGen
28 | , 'Functor': MaybeGen
29 | , 'Applicative': MaybeMonoidGen
30 | , 'Monad': MaybeGen
31 | });
32 |
33 | describe('Monoid', function(){
34 | it('ignores the nulls and combines the contained monoid', function() {
35 | assert.deepEqual(mconcat([Just("hi, "), Nothing(), Just("guy")]), Just("hi, guy"));
36 | });
37 | });
38 |
39 | describe('Functor', function(){
40 | it('works with map', function(){
41 | var getStreet = compose(map(add('my email is ')), safeGet('email'));
42 | assert.deepEqual(getStreet(user), Just('my email is sally@test.com'));
43 | });
44 | });
45 |
46 | describe('Applicative', function(){
47 | it('runs if values are present', function() {
48 | assert.deepEqual(Just(add('yo ')).ap(Just('dawg')), Just('yo dawg'));
49 | });
50 |
51 | it('fails on null', function() {
52 | assert.deepEqual(Just(add('yo ')).ap(Just('dawg')).ap(Nothing()), Nothing());
53 | });
54 |
55 | it('applys the function to the value within the context of Maybe', function() {
56 | assert.deepEqual(ap(Just(add(2)), Just(3)), Just(5));
57 | });
58 |
59 | it('lifts a function into the maybe context', function() {
60 | assert.deepEqual(liftA2(add, Just(2), Just(3)), Just(5));
61 | });
62 | });
63 |
64 | describe('Monad', function(){
65 | var flatSafeTraverseStreetName = compose( mjoin
66 | , map(safeGet('name'))
67 | , mjoin
68 | , map(safeGet('street'))
69 | , safeGet('address')
70 | );
71 |
72 | it('flattens the nested maps', function(){
73 | var user = {email: "sally@test.com", address: {street: {number: 23, name: "Winston"}}}
74 | assert.deepEqual(flatSafeTraverseStreetName(user), Just('Winston'));
75 | })
76 |
77 | it('fails if null', function(){
78 | var user = {email: "sally@test.com", address: null}
79 | assert.deepEqual(flatSafeTraverseStreetName(user), Nothing());
80 | })
81 |
82 | it('binds a value to the function', function(){
83 | var result = chain(function(three){
84 | return chain(function(four){
85 | return Just(three + four);
86 | }, Just(4))
87 | }, Just(3));
88 | assert.deepEqual(result, Just(7));
89 | })
90 | });
91 | describe('Other', function() {
92 | it('is traversable', function() {
93 | var f = function(x){ return [x]; }
94 | assert.deepEqual(traverse(f, Array.of, Just(1)), [Just(1)]);
95 | })
96 |
97 | it('is foldable', function() {
98 | assert.deepEqual(foldMap(concat([1,2]), Just([3,4])), [1,2,3,4])
99 | assert.deepEqual(toList(Just(3)), [3])
100 | });
101 | });
102 | });
103 |
--------------------------------------------------------------------------------
/test/monoids.js:
--------------------------------------------------------------------------------
1 | require('../pointfree').expose(global)
2 |
3 |
4 | var assert = require("assert")
5 | , quickCheckLaws = require('./helper').quickCheckLaws
6 | , curry = require('lodash.curry')
7 | , claire = require('claire')
8 | , _ = claire.data
9 | , asGenerator = claire.asGenerator
10 | , monoids = require('../instances/monoids')
11 | , forAll = claire.forAll
12 | ;
13 |
14 | var _stubFn = function() { return function() { return _.Str.next().value }; };
15 | var FunGen = asGenerator(_stubFn)
16 |
17 | describe('Monoids', function(){
18 | it('gets the max', function() {
19 | assert.equal(monoids.getResult(mappend(monoids.Max(12), monoids.Max(20))), 20)
20 | });
21 |
22 | it('gets the min', function() {
23 | assert.equal(monoids.getResult(mappend(monoids.Min(12), monoids.Min(20))), 12)
24 | });
25 |
26 | it('gets the sum', function() {
27 | assert.equal(monoids.getResult(mappend(monoids.Sum(12), monoids.Sum(20))), 32)
28 | });
29 |
30 | it('gets the product', function() {
31 | assert.equal(monoids.getResult(mappend(monoids.Product(2), monoids.Product(20))), 40)
32 | });
33 |
34 | it('gets the disjunction', function() {
35 | assert.equal(monoids.getResult(mappend(monoids.Any(true), monoids.Any(false))), true)
36 | assert.equal(monoids.getResult(mappend(monoids.Any(false), monoids.Any(false))), false)
37 | });
38 |
39 | it('gets the conjunction', function() {
40 | assert.equal(monoids.getResult(mconcat([monoids.All(true), monoids.All(false)])), false)
41 | assert.equal(monoids.getResult(mappend(monoids.All(true), monoids.All(true))), true)
42 | });
43 |
44 | it('runs the functions then gets the conjuction', function() {
45 | var f = function(x) { return monoids.Any(x > 1); }
46 | , g = function(y) { return monoids.Any(y > 2); }
47 | ;
48 |
49 | // var t = compose(monoids.getResult, monoids.mconcat, fmap(monoids.All), mconcat([f, g]))
50 | // assert.equal(t(2, 3), false)
51 | assert.deepEqual(mconcat([f, g])(4, 6), monoids.Any(true))
52 | assert.deepEqual(mconcat([f, g])(0, 0), monoids.Any(false))
53 | });
54 |
55 | });
56 |
57 |
58 |
--------------------------------------------------------------------------------
/test/string.js:
--------------------------------------------------------------------------------
1 | require('../pointfree').expose(global)
2 |
3 |
4 | var assert = require("assert")
5 | , quickCheckLaws = require('./helper').quickCheckLaws
6 | , curry = require('lodash.curry')
7 | , claire = require('claire')
8 | , _ = claire.data
9 | , forAll = claire.forAll
10 | ;
11 |
12 | describe('String', function(){
13 | quickCheckLaws({ 'Semigroup': _.Str
14 | , 'Monoid': _.Str
15 | });
16 | });
17 |
18 |
19 |
--------------------------------------------------------------------------------
/util.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var Constructor = function(f) {
4 | var x = function(){
5 | if(!(this instanceof x)){
6 | var inst = new x();
7 | f.apply(inst, arguments);
8 | return inst;
9 | }
10 | f.apply(this, arguments);
11 | };
12 |
13 | return x;
14 | };
15 | exports.Constructor = Constructor;
16 | var makeType = function(f) {
17 | f = f || function(v){ this.val = v; }
18 | return Constructor(f);
19 | };
20 | exports.makeType = makeType;
21 |
22 | var subClass = function(superclass, constructr) {
23 | var x = makeType();
24 | x.prototype = new superclass();
25 | x.prototype.constructor=constructr;
26 | return x;
27 | }
28 | exports.subClass = subClass;
29 |
30 | var K = function(x){return function(){return x;};};
31 | exports.K = K;var I = function(x){return x;};
32 | exports.I = I;
--------------------------------------------------------------------------------