mercoledì 4 novembre 2009

Rails: usare template grafici con Rails




In this screencast, I show you how to easily add a layout with built-in menus to your existing Rails application.

martedì 3 novembre 2009

Functional.js - High order function - Parte 3 : Function composition

Nella programmazione funzionale per function composition s'intende la combinazione di funzioni semplici all'interno di una funzione più complessa.
Questo composizione, permette di creare una funzione che è il risultato di una concatenazione di funzioni.
Unica condizione è che queste funzioni accettino come parametro di input e di return un unico parametro.

Functional.js mette a disposizione 2 funzioni per la function composition: sequence e compose.
Vediamo un esempio pratico, scrivendo:

Functional.install()

var fnSequence=sequence('+1','+2','+3','*100');
console.log("sequence -> (100+1+2+3)*100=",fnSequence(100));

var fnCompose=compose('+1','+2','+3','*100');
console.log("compose -> (100*100)+3+2+1=",fnCompose(100));


otteniamo come risultato:

sequence -> (100+1+2+3)*100= 10600
compose -> (100*100)+3+2+1= 10006

come vedete sequence crea una concatenazione dal primo all'ultimo parametro-funzione, mentre compose dall'ultimo al primo parametro-funzione.
Ogni String Lambda è una funziona unaria, che accetta un unico parametro di input e lo ritorna trasformato in qualcos'altro.

Il principio è molto simile alla pipe della shell di linux:
tail -f | grep error

Come sempre è possibile usare le HOF che lavorano sulle liste, come la map, per usare la function composition:
scriviamo questo codice

var lista=[1,2,3,4,5,6,7,8,9,10];

var ret=map(sequence('+1','+2','+3','*100'),list);
console.log("map(sequence('+1','+2','+3','*100'),list)=",ret);

var ret=map(compose('+1','+2','+3','*100'),list);
console.log("map(compose('+1','+2','+3','*100'),list)=",ret);

e otteniamo come risultato:

map(sequence('+1','+2','+3','*100'),list)= [700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600]
map(compose('+1','+2','+3','*100'),list)= [106, 206, 306, 406, 506, 606, 706, 806, 906, 1006]

Nel prossimo Post su Functional.js chiuderemo il discorso introduttivo sulle HOF con l'introduzione dei concetti di currying e partial. Dopo di che vedremo qualche
esempio pratico di programmazione funzionale da usare nella routine di tutti i giorni con javascript.

Thinking Functionally in Ruby

Per chi vuole approdonfire la programmazione funzionale in ruby:

Functional.js - High order function - Parte 2 : Funzioni condizionali

And Or e Not sono tre HOF che accettano come parametri delle funzioni, che vengono utilizzate per generare una nuova funzione basate sulle condizioni delle funzioni di input.
Vediamo qualche esempio

Functional.install()

var ret=and('>5','<10')(8);
console.log(">5 and <10",ret);


var ret=or('>5','<10')(8);
console.log(">5 or <10",ret);

var ret=not('>5')(8);
console.log("not >5",ret);


e otterremo come risultato:

>5 and <10 true
>5 or <10 true
not >5 false

Possiamo usare queste HOF condizionali anche con la funzione filter applicata a una lista:

Functional.install()

var list=[1,2,3,4,5,6,7,8,9,10];

var ret=filter(and('>4','<9'),list);
console.log(">4 and <9",ret);

var ret=filter(not(and('>4','<9')),list);
console.log("not (>4 and <9)",ret);

e otteniamo:

>4 and <9 [5, 6, 7, 8]
not (>4 and <9) [1, 2, 3, 4, 9, 10]

lunedì 2 novembre 2009

Functional.js - High order function - Parte 1

In questo secondo post su Functional.js vediamo l'introduzione alle High Order Function (HOF).
Le HOF nella programmazione funzionale (FP), sono funzioni che possono manipolare altre funzione, accettarle come parametri, creare nuove funzioni, o trasformarle in altre funzioni.

Un esempio classico che viene usato nella FP, con l'uso delle closure, è l'accumulator:

Se provate a eseguire questo codice:

var generateAccumulator=function(start) {
   return function(n) {
      start=start+n;
      console.log(start);
      return start;
   }
};

fnAcc=generateAccumulator(10);
fnAcc(1);
fnAcc(2);
fnAcc(3);

otterrete come risultato:

11
13
16

Come vedete grazie alle closure è possibile mantenere lo stato delle variabili interne della funzione (in questo caso la variabile start inizializzata come parametro).

Functional.js ci mette a disposizione una serie di funzioni molto usate nella FP. In questo articolo approfondiamo quelle che lavorano su una lista e che in parte sono state mutuate dal LISP:
mapselect, some, every e reduce.

Partiamo con un esempio pratico, per poi entrare in dettaglio su quello che abbiamo ottenuto.
Intanto dovete scaricarvi la libreria functional.js che trovate a questo indirizzo http://github.com/osteele/functional-javascript, inserirla dentro una pagina html.
Poi caricate la pagina dentro firefox, aprite firebug e dentro la finestra di console scrivete questo codice:

Functional.install();

Functional.install();

var lst=[1,2,3,4,5,6,7,8,9,10];

var ret=map('+100',lst);
console.log("map",ret);

var ret=filter('>5',lst);
console.log("log",ret);

var ret=some('>5',lst);
console.log("some",ret);

var ret=every('>5',lst);
console.log("every",ret);

var ret=reduce('x+y',0,lst);
console.log("reduce",ret);


e otterremo questo come output:

map [101, 102, 103, 104, 105, 106, 107, 108, 109, 110]
log [6, 7, 8, 9, 10]
some true
every false
reduce 55

Come vedere queste funzioni accetta 2 parametri (al di fuori di reduce) una lambda String  (vedi questo articolo come introduzione) e una lista:
map -> trasforma una lista in un'altra lista (fa un mapping)
filter -> applica un filtro a una lista e ne ritorna una filtrata
every -> torna true se tutti gli elementi della lista soddisfano la condizione della funzione
some -> torna true se almeno un elemento della lista soddisfa la condizione della funzione
reduce -> accetta tre parametri (una funzione di trasformazione, un valore o oggetto iniziale e la lista),  applica una riduzione della lista
          usando la funzione di trasformazione, fino a ritornare un unico oggetto (è l'equivalente di inject in smalltalk o ruby, e di fold).
        
Con queste 5 funzioni abbiamo quasi tutto per poter manipolare con tranquillità strutture dati basate su liste.
Ovviamente possiamo usare anche strutture dati più complesse come liste di oggetti:

Functional.install();

var persons=[
  {name:'paolo',surname:'rossi',age:35},
  {name:'mario', surname:'bianchi', age:55 },
  {name:'luigi',surname:'neri',age:22}
];

var ret=map('.name',persons);
console.log("lista dei nomi",ret)

var ret=filter('.age < 40',persons);
console.log("persone minori di 40 anni di età",ret);

var ret=every('.age > 10',persons);
console.log('tutti hanno più di 10 anni?',persons);

var ret=some('.age > 30',persons);
console.log('almeno una persona ha più di 30 anni?',persons);        
        
Vi ricordo che queste funzioni possono ricevere come parametri funzione sia string lambda che normali funzioni javascript

domenica 1 novembre 2009

dojo e jQuery: divergenze su map

Dojo e jQuery sono 2 libreria che uso spesso e che adoro molto, soprattutto perchè hanno 2 approcci molto differenti sul come scrivere applicazioni web.

In particolare l'uso della funzione map differisce un pò tra le 2 librerie, soprattutto in 2 punti:

1) utilizzo del this:
   jQuery usa il this come riferimento degli oggetti che devono esssere mappati mentre Dojo passa il riferimento come parametro.

   in jQuery infatti scriveremo cosi:
      $([1,2,3,4,5,6,7,8,9,10]).map(function() {  return this +5 });

   in Dojo invece:
      dojo.map([1,2,3,4,5,6,7,8,9,10],function(el) { return el + 5});

2) return null:

    in jQuery se ritorniamo un null l'oggetto su cui si sta mappando viene tolto dalla lista generata dalla   funzione map:
     $([1,2,3,4,5,6,7,8,9,10].map(function() {  return this>5 ? this : null });
    ci ritornera [6,7,8,9,10]

    in Dojo invece:
       dojo.map([1,2,3,4,5,6,7,8,9,10],function(el) {  return el>5 ? this : null });
       ritornera [1,2,3,4,5,null,null,null,null,null]
    Questo perchè la map in jQuery può essere usata come funzione di filter oltre che di mapping.

   in dojo per avere un filtro invece dovremo usare la funzione dojo.filter:
      dojo.filter([1,2,3,4,5,6,7,8,9,10],function(el) {  return el>6 });