Programare funcţională în Javascript Alexandru Badiu
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
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
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
Procedurală Ce este programarea funcţională? #include <stdio.h> #include <stdlib.h> int main(void) { puts("Hello World!"); return EXIT_SUCCESS; } Programare funcțională în Javascript - Alexandru Badiu
OO Ce este programarea funcţională? class HelloWorld { static public void main( String args[] ) { System.out.println( "Hello World!" ); } } Programare funcțională în Javascript - Alexandru Badiu
Logică Ce este programarea funcţională? ?- write(”Hello World!”), nl. Programare funcțională în Javascript - Alexandru Badiu
Funcţională Ce este programarea funcţională? (alert “Hello World!”) Programare funcțională în Javascript - Alexandru Badiu
Limbaje ezoterice Ce este programarea funcţională? HAI CAN HAS STDIO? VISIBLE "HAI WORLD!" KTHXBYE Programare funcțională în Javascript - Alexandru Badiu
HTML Ce este programarea funcţională? <p>HTML nu este un limbaj de programare.</p> Programare funcțională în Javascript - Alexandru Badiu
Javascript Ce este programarea funcţională? Programare funcțională în Javascript - Alexandru Badiu
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
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
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
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
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
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
Exemple Funcţii anonime jQuery("div.autoo-more a").click(function(event) { mf = jQuery(this).parent().prev(); mf.toggle(); if (mf.css('display') == 'none') { jQuery(this).html('Mai multe &raquo;'); } else { jQuery(this).html('&laquo; Mai putine'); } return false; }); Programare funcțională în Javascript - Alexandru Badiu
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
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
Exemple Funcţii imbricate function imbri(){ var mesaj = "salut"; function imbri2() { console.log(mesaj); }; imbri2(); }; imbri(); // salut function imbri(mesaj){ ( function () { console.log(mesaj); } ) (mesaj); }; imbri("test"); // test Programare funcțională în Javascript - Alexandru Badiu
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
Exemple Închideri Funcţia întoarsă are acces la variabila msg function say(what) { var msg = "Mesaj: " + 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 = "Mesaj: " + what; return ret; } say('unu')(); // Mesaj: unu say('doi')(); // Mesaj: doi Programare funcțională în Javascript - Alexandru Badiu
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) ? "POST" : "GET"; 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
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
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
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
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: "text", success: function(data, status){ this.templates['anunt-container.ejs'] = data; this.loaded++; } }); this.toload++; ... Programare funcțională în Javascript - Alexandru Badiu
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: "text", success: function(data, status){ that.templates['anunt-container.ejs'] = data; that.loaded++; } }); this.toload++; ... Programare funcțională în Javascript - Alexandru Badiu
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
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
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
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
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("foo.php", update.curry(window, 'elem1')); $.get("bar.php", update.curry(window, 'elem2')); function update(data) { $(this).html(data); } $.get("foo.php", update.curry($('elem1'))); $.get("bar.php", update.curry($('elem2'))); Programare funcțională în Javascript - Alexandru Badiu
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
? Alexandru Badiu i@voidberg.org http://voidberg.org

Functional programming in java script

  • 1.
    Programare funcţională înJavascript Alexandru Badiu
  • 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("Hello World!"); 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( "Hello World!" ); } } 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 "HAI WORLD!" 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("div.autoo-more a").click(function(event) { mf = jQuery(this).parent().prev(); mf.toggle(); if (mf.css('display') == 'none') { jQuery(this).html('Mai multe &raquo;'); } else { jQuery(this).html('&laquo; 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 = "salut"; function imbri2() { console.log(mesaj); }; imbri2(); }; imbri(); // salut function imbri(mesaj){ ( function () { console.log(mesaj); } ) (mesaj); }; imbri("test"); // 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 = "Mesaj: " + 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 = "Mesaj: " + 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) ? "POST" : "GET"; 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: "text", 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: "text", 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("foo.php", update.curry(window, 'elem1')); $.get("bar.php", update.curry(window, 'elem2')); function update(data) { $(this).html(data); } $.get("foo.php", update.curry($('elem1'))); $.get("bar.php", 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
  • 36.
    ? Alexandru Badiu i@voidberg.org http://voidberg.org