Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 178 lines (149 sloc) 4.881 kb
60abab6 @shichuan added function patterns
authored
1 <!doctype html>
2 <html lang="en">
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
3 <head>
4 <title>JavaScript Patterns</title>
5 <meta charset="utf-8">
6 </head>
7 <body>
8 <script>
9 /* Title: Currying
10 Description: used to create new functions dynamically by partially applying a set of arguments
11 */
12
13 /***
14 function application
15 ***/
8629df2 @Grom-S few typos corrected
Grom-S authored
16 // define a function
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
17 var sayHi = function (who) {
18 return "Hello" + (who ? ", " + who : "") + "!";
19 };
a2b6705 @shichuan edited function patterns
authored
20
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
21 // invoke a function
22 sayHi(); // "Hello"
23 sayHi('world'); // "Hello, world!"
a2b6705 @shichuan edited function patterns
authored
24
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
25 // apply a function
26 sayHi.apply(null, ["hello"]); // "Hello, hello!"
a2b6705 @shichuan edited function patterns
authored
27
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
28 var alien = {
29 sayHi:function (who) {
30 return "Hello" + (who ? ", " + who : "") + "!";
31 }
32 };
a2b6705 @shichuan edited function patterns
authored
33
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
34 alien.sayHi('world'); // "Hello, world!"
35 sayHi.apply(alien, ["humans"]); // "Hello, humans!"
a2b6705 @shichuan edited function patterns
authored
36
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
37 // the second is more efficient, saves an array
38 sayHi.apply(alien, ["humans"]); // "Hello, humans!"
39 sayHi.call(alien, "humans"); // "Hello, humans!"
a2b6705 @shichuan edited function patterns
authored
40
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
41 /***
42 partial application
43 ***/
a2b6705 @shichuan edited function patterns
authored
44
8629df2 @Grom-S few typos corrected
Grom-S authored
45 // for illustration purposes
46 // not valid JavaScript
a2b6705 @shichuan edited function patterns
authored
47
8629df2 @Grom-S few typos corrected
Grom-S authored
48 // we have this function
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
49 function add(x, y) {
50 return x + y;
51 }
a2b6705 @shichuan edited function patterns
authored
52
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
53 // and we know the arguments
54 add(5, 4);
a2b6705 @shichuan edited function patterns
authored
55
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
56 // step 1 -- substitute one argument
8629df2 @Grom-S few typos corrected
Grom-S authored
57 function add(5, y) {
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
58 return 5 + y;
59 }
a2b6705 @shichuan edited function patterns
authored
60
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
61 // step 2 -- substitute the other argument
8629df2 @Grom-S few typos corrected
Grom-S authored
62 function add(5, 4) {
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
63 return 5 + 4;
64 }
a2b6705 @shichuan edited function patterns
authored
65
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
66 /***
67 currying
68 ***/
a2b6705 @shichuan edited function patterns
authored
69
8629df2 @Grom-S few typos corrected
Grom-S authored
70 // a curried add()
71 // accepts partial list of arguments
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
72 function add(x, y) {
73 var oldx = x, oldy = y;
74 if (typeof oldy === "undefined") { // partial
75 return function (newy) {
76 return oldx + newy;
77 }
78 }
79 // full application
80 return x + y;
81 }
82
83 // test
84 typeof add(5); // "function"
85 add(3)(4); // 7
86
87 // create and store a new function
88 var add2000 = add(2000);
89 add2000(10); // 2010
90
91 function schonfinkelize(fn) {
92 var slice = Array.prototype.slice,
93 stored_args = slice.call(arguments, 1);
94 return function () {
95 var new_args = slice.call(arguments),
96 args = stored_args.concat(new_args);
97 return fn.apply(null, args);
98 };
99 }
100
101 // reference
102 // http://www.jspatterns.com/
103 // http://shop.oreilly.com/product/9780596806767.do?sortby=publicationDate
104
105 // Here's a generic curry function (from kybernetikos):
106 // It's slightly more complex than the common examples of currying (e.g. the one above), but that's because
107 // the function can afterwards be called either in the normal way, or in the curried way.
108 // If you call a 3 argument curried function with it, the returned function *is also curried*.
109 // e.g. you can write func(arg1)(arg2)(arg3) or func(arg1, arg2, arg3) or func(arg1)(arg2, arg3) etc...
110
111 /* the curry procedure needs to know how many arguments are required before it should calculate the result */
112 function curry(func, minArgs) {
113 if (minArgs == undefined) {
114 minArgs = 1;
115 }
116
117 function funcWithArgsFrozen(frozenargs) {
118 return function () {
8629df2 @Grom-S few typos corrected
Grom-S authored
119 // could do an optimisation here - if called with no arguments
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
120 // return exactly this function.
121 var args = Array.prototype.slice.call(arguments);
122 var newArgs = frozenargs.concat(args);
123 if (newArgs.length >= minArgs) {
124 return func.apply(this, newArgs);
125 } else {
126 return funcWithArgsFrozen(newArgs);
127 }
128 };
129 }
130
131 return funcWithArgsFrozen([]);
46592e9 @kybernetikos Update function-patterns/currying.html
kybernetikos authored
132 }
f1b4f9a Proper indentation using tabs (both HTML and JS)
Lars Kappert authored
133
134 /* Here are some example uses - I use these with a functional immutable list structure implemented in js
135 but they also work ok for normal higher order functions over arrays.
136 */
137
138 var plus = curry(function () {
139 var result = 0;
140 for (var i = 0; i < arguments.length; ++i) {
141 result += arguments[i];
142 }
143 return result;
144 }, 2);
145
146 /* Now you can call
147 plus(3,2) // normal call
148 plus(3) // partial application (returns a function that adds 3 to its argument)
149 plus(3)(2) // complete application (returns 5)
150 plus()(3)()()(2) // returns 5
151 plus(3, 2, 4, 5) // the normal call can optionally take more than the minimum number of arguments
152 plus(3)(2, 3, 5) // the last application can too.
153 */
154
155 var minus = curry(function (x) {
156 var result = x;
157 for (var i = 1; i < arguments.length; ++i) {
158 result -= arguments[i];
159 }
160 return result;
161 }, 2);
162
163 /* flip switches the order of the first two arguments on a function. It is curried itself and
164 the function it returns is curried too. Particularly useful if you want a function that subtracts a number */
165
166 var flip = curry(function (func) {
167 return curry(function (a, b) {
168 return func(b, a);
169 }, 2);
170 });
171
172 /* for example
173 minus(5) // returns a function that takes its argument away from 5
174 flip(minus)(5) // returns a function that takes 5 away from its argument
175 */
176 </script>
177 </body>
60abab6 @shichuan added function patterns
authored
178 </html>
Something went wrong with that request. Please try again.