2. Conţinut
Ce este programarea funcţională?
Funcţii de ordin înalt
Funcţii anonime
Funcţii imbricate
Închideri
Currying
Programare funcțională în Javascript - Alexandru Badiu
3. Funcţională? Ce este programarea funcţională?
Programarea funcţională este o paradigmă de
programare
Se pune accent pe evaluarea expresiilor şi nu pe
execuţia comenzilor
Expresiile sunt funcţii
Constante vs variabile
Lisp, Erlang, Haskell, OCaml
Dacă ai scris cod Javascript sau Ruby atunci
probabil ai folosit concepte din programarea
funcţională fără să ştii
Programare funcțională în Javascript - Alexandru Badiu
4. Paradigme? Ce este programarea funcţională?
O paradigmă de programare e un stil de a programa
Concepte pentru elementele unui program (funcţii,
variabile, obiecte etc)
Concepte pentru paşii unui calcul (evaluare,
atribuire etc)
Un limbaj de programare poate oferi suport pentru
mai multe paradigme
Programare funcțională în Javascript - Alexandru Badiu
5. Procedurală Ce este programarea funcţională?
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
puts(quot;Hello World!quot;);
return EXIT_SUCCESS;
}
Programare funcțională în Javascript - Alexandru Badiu
6. OO Ce este programarea funcţională?
class HelloWorld {
static public void main( String args[] ) {
System.out.println( quot;Hello World!quot; );
}
}
Programare funcțională în Javascript - Alexandru Badiu
7. Logică Ce este programarea funcţională?
?- write(”Hello World!”), nl.
Programare funcțională în Javascript - Alexandru Badiu
8. Funcţională Ce este programarea funcţională?
(alert “Hello World!”)
Programare funcțională în Javascript - Alexandru Badiu
9. Limbaje ezoterice Ce este programarea funcţională?
HAI
CAN HAS STDIO?
VISIBLE quot;HAI WORLD!quot;
KTHXBYE
Programare funcțională în Javascript - Alexandru Badiu
10. HTML Ce este programarea funcţională?
<p>HTML nu este un limbaj de programare.</p>
Programare funcțională în Javascript - Alexandru Badiu
11. Javascript Ce este programarea funcţională?
Programare funcțională în Javascript - Alexandru Badiu
12. Definiţie Funcţii de ordin înalt
Funcţiile sunt de ordin înalt
Sunt obiecte
Au proprietăţi
Pot fi transmise altor funcţii
Pot fi întoarse ca rezultat
Pot fi create dinamic
Programare funcțională în Javascript - Alexandru Badiu
13. Exemple Funcţii de ordin înalt
function say(what) {
console.log(what);
}
var say = function (what) {
console.log(what);
}
say('hello');
// hello
var spune = say;
spune('salut');
// salut
say = function (what) {
console.log('nu vreau');
}
spune('ceva');
// ceva
Programare funcțională în Javascript - Alexandru Badiu
14. Exemple Funcţii de ordin înalt
var gen_func = function (op) {
switch (op) {
case '+':
return function () { var r = arguments[0]; for (var i=1; i<arguments.length; i++ ) r +=
arguments[i]; return r; }
case '-':
return function () { var r = arguments[0]; for (var i=1; i<arguments.length; i++ ) r -=
arguments[i]; return r; }
case '*':
return function () { var r = arguments[0]; for (var i=1; i<arguments.length; i++ ) r *=
arguments[i]; return r; }
case '/':
return function () { var r = arguments[0]; for (var i=1; i<arguments.length; i++ ) r /=
arguments[i]; return r; }
}
}
var add = gen_func('+');
add;
// function () { var r = arguments[0]; for (var i = 1; i < arguments.length; i++) { r +=
arguments[i]; } return r; }
add(1,2,3);
// 6
var mul = gen_func('*');
mul(4,5,6);
// 120
Programare funcțională în Javascript - Alexandru Badiu
15. Exemple Funcţii de ordin înalt
var compune = function (f, g) {
return function (x) { return f(g(x)); }
};
var a = function (x) {
return x*x;
};
var b = function (x) {
return x/2;
};
var c = compune(a, b);
var d = compune(b, a);
c(6);
// 9
d(6);
// 18
Programare funcțională în Javascript - Alexandru Badiu
16. Definiţie Funcţii anonime
Funcţii fără nume
Folosite atunci când codul trebuie rulat o singură
dată
Folosite la sortări, căutari
Folosite la evenimente
Programare funcțională în Javascript - Alexandru Badiu
17. Exemple Funcţii anonime
(function (what) { console.log(what)}) ('functie anonima');
// functie anonima
( function (x) {
if (x<2) return x;
return x * arguments.callee(x - 1);
}) (3);
// 6
Programare funcțională în Javascript - Alexandru Badiu
18. Exemple Funcţii anonime
jQuery(quot;div.autoo-more aquot;).click(function(event) {
mf = jQuery(this).parent().prev();
mf.toggle();
if (mf.css('display') == 'none') {
jQuery(this).html('Mai multe »');
}
else {
jQuery(this).html('« Mai putine');
}
return false;
});
Programare funcțională în Javascript - Alexandru Badiu
19. Exemple Funcţii anonime
var v = [ 6, 12, 19, 8, 40 ];
v.sort();
// 12,19,40,6,8
v.sort(function (x, y) { return x - y; });
// 6,8,12,19,40
v.sort(function (x, y) { return y - x; });
// 40,19,12,8,6
function Cauta(v, f)
{
for (var i = 0; i < v.length; i++)
if (f(v[i])) { return i; }
return -1;
}
Cauta(v, function (x) { return x > 10; });
// 0
Cauta(v, function (x) { return x < 10; });
// 3
Programare funcțională în Javascript - Alexandru Badiu
20. Definiţie Funcţii imbricate
Funcţii definite în interiorul altor funcţii
Funcţii anonime
Funcţii non-anonime
Programare funcțională în Javascript - Alexandru Badiu
21. Exemple Funcţii imbricate
function imbri(){
var mesaj = quot;salutquot;;
function imbri2() {
console.log(mesaj);
};
imbri2();
};
imbri();
// salut
function imbri(mesaj){
( function () { console.log(mesaj); } ) (mesaj);
};
imbri(quot;testquot;);
// test
Programare funcțională în Javascript - Alexandru Badiu
22. Definiţie Închideri
În engleză: closures
Funcţiile imbricate au acces la variabilele din
funcţia părinte
Chiar şi după ce execuţia funcţiei părinte s-a
terminat
Funcţia = (Funcţia imbricată, Variabile locale)
Variabilele nu sunt copiate ci este păstrată o
referinţă
Programare funcțională în Javascript - Alexandru Badiu
23. Exemple Închideri
Funcţia întoarsă are acces la variabila msg
function say(what) {
var msg = quot;Mesaj: quot; + what;
return function () { console.log(msg); };
}
say('unu')();
// Mesaj: unu
say('doi')();
// Mesaj: doi
function say(what) {
var ret = function () { console.log(msg); };
var msg = quot;Mesaj: quot; + what;
return ret;
}
say('unu')();
// Mesaj: unu
say('doi')();
// Mesaj: doi
Programare funcțională în Javascript - Alexandru Badiu
24. Exemple Închideri
Acelaşi lucru este valabil şi pentru funcţii declanşate
de evenimente
function sendRequest(url,callback,postData) {
var req = createXMLHTTPObject();
if (!req) { return; }
var method = (postData) ? quot;POSTquot; : quot;GETquot;;
req.open(method,url,true);
req.setRequestHeader('User-Agent','XMLHTTP/1.0');
if (postData) {
req.setRequestHeader('Content-type','application/x-www-form-urlencoded');
}
req.onreadystatechange = function () {
if (req.readyState != 4) return;
if (req.status != 200 && req.status != 304) {
alert('HTTP error ' + req.status);
return;
}
callback(req);
}
if (req.readyState == 4) return;
req.send(postData);
}
Programare funcțională în Javascript - Alexandru Badiu
25. Exemple Închideri
Mai multe funcţii imbricate au acces la aceeaşi
închidere
function setup() {
var num = 21;
afiseaza = function () {
console.log(num);
}
incrementeaza = function () {
num++;
}
}
setup();
afiseaza();
// 21
incrementeaza();
afiseaza();
// 22
setup();
afiseaza();
// 21
Programare funcțională în Javascript - Alexandru Badiu
26. Gotchas Închideri
Ce este afisat?
function pregateste_functii(num) {
var res = [];
for (var i=0; i<num; i++) {
res.push(function () { console.log(i); });
}
return res;
}
var funcs = pregateste_functii(4);
for (var i=0; i<funcs.length; i++) {
funcs[i]();
}
Programare funcțională în Javascript - Alexandru Badiu
27. Gotchas Închideri
Ce este afisat?
function pregateste_functii(num) {
var res = [];
for (var i=0; i<num; i++) {
res.push(function () { console.log(i); });
}
return res;
}
var funcs = pregateste_functii(4);
for (var i=0; i<funcs.length; i++) {
funcs[i]();
}
// 4
// 4
// 4
// 4
Programare funcțională în Javascript - Alexandru Badiu
28. Gotchas Închideri
this nu se comporta ca în alte limbaje
În acest caz this.loaded se referă la ajax_ob.loaded
AclinkESM.prototype.loadTemplates = function () {
if (this.individual_templates) {
this.templates = [];
jQuery.ajax({
url: this.config.t_dir + 'anunt-container.ejs',
processData: true,
dataType: quot;textquot;,
success: function(data, status){
this.templates['anunt-container.ejs'] = data;
this.loaded++;
}
});
this.toload++;
...
Programare funcțională în Javascript - Alexandru Badiu
29. Gotchas Închideri
Soluţia: copierea lui this în altă variabilă, tipic that
sau self
AclinkESM.prototype.loadTemplates = function () {
var that = this;
if (this.individual_templates) {
this.templates = [];
jQuery.ajax({
url: this.config.t_dir + 'anunt-container.ejs',
processData: true,
dataType: quot;textquot;,
success: function(data, status){
that.templates['anunt-container.ejs'] = data;
that.loaded++;
}
});
this.toload++;
...
Programare funcțională în Javascript - Alexandru Badiu
30. Definiţie Currying
Numit după Haskell Curry
Evaluarea parţială a funcţiilor
Modifică scope-ul la rulare
Matematic:
f (X x Y) -> Z
curry(f):X -> (Y -> Z)
Non matematic:
console.log(aduna(2, 3));
// 5
var aduna4 = aduna(4);
console.log(aduna4(10));
// 14
Programare funcțională în Javascript - Alexandru Badiu
31. Implementare Currying
Varianta simplă
function aduna(a) {
return function (b) { return a + b; };
}
var aduna4 = aduna(4);
var aduna10 = aduna(10);
aduna4(5);
// 9
aduna10(5);
// 15
Ideal ar fi să putem aplica procedeul la orice funcţie,
fără să o modificăm
function aduna(a, b) {
return a + b;
}
var aduna4 = aduna.curry(4);
Programare funcțională în Javascript - Alexandru Badiu
32. Implementare Currying
Function.prototype.curry = function() {
var fn = this, args = [];
for (var i = 0; i < arguments.length; i++)
args.push(arguments[i]);
return function() {
for (var i = 0; i < arguments.length; i++)
args.push(arguments[i]);
return fn.apply(window, args);
};
};
function aduna(a, b) {
return a + b;
}
a = aduna.curry(5);
b = aduna.curry(10);
a(10); // 15
b(10); // 20
Programare funcțională în Javascript - Alexandru Badiu
33. Implementare Currying
Uneori este utilă schimbarea scope-ului
bind din Prototype, dojo.lang.curry
Function.prototype.curry = function(scope) {
var fn = this, args = [];
var scope = scope || window;
for (var i = 1; i < arguments.length; i++)
args.push(arguments[i]);
return function() {
for (var i = 0; i < arguments.length; i++)
args.push(arguments[i]);
return fn.apply(scope, args);
};
};
Programare funcțională în Javascript - Alexandru Badiu
34. Exemple Currying
function sayHello(msg) {
console.log(msg + 'n You clicked on ' + this.id);
}
var el1 = document.getElementById('element1');
var el2 = document.getElementById('element2');
el1.addEventListener('click', sayHello.curry(el1, 'Hello'), false);
el2.addEventListener('click', sayHello.curry(el2, 'Salut'), false);
function update(elem, data) {
$(elem).html(data);
}
$.get(quot;foo.phpquot;, update.curry(window, 'elem1'));
$.get(quot;bar.phpquot;, update.curry(window, 'elem2'));
function update(data) {
$(this).html(data);
}
$.get(quot;foo.phpquot;, update.curry($('elem1')));
$.get(quot;bar.phpquot;, update.curry($('elem2')));
Programare funcțională în Javascript - Alexandru Badiu
35. Resurse
http://www.joelonsoftware.com/items/2006/08/01.html
http://osteele.com/archives/2007/07/functional-javascript
http://invisibleblocks.wordpress.com/2007/02/23/functional-
programming-in-javascript-and-ruby/
Programare funcțională în Javascript - Alexandru Badiu