samedi 26 mai 2012

Utilisation de Proc#curry

Avant propos
On m'a souvent fait remarqué que je ne faisait rien dans et pour Funkywork alors j'ai décidé d'écrire un micro-article qui tire partit d'une petite astuce présentée précédemment.
Sachez tout d'abord que cet article n'a pas pour objectif de présenter un fait, "une vérité absolue", mais une manière que je considère comme élégante (et potentiellement amusante) de résoudre certains problèmes.

Contenu de l'article
Ce billet présentera une manière d'utiliser la méthode Curry de la classe Proc, car comme Pierre en avait parlé dans son article, on en voit rarement l'intérêt (cf : L'article en question ).
Cette manière n'est certainement pas la seule, ni même la meilleure, mais elle a au moins le mérite d'être originale.

Contextualisation
Pour un projet "divers", j'ai du manipuler des projectiles. Il existe plusieurs manière de déplacer un projectile, j'ai choisis d'utiliser une fonction.
L'équation d'une fonction linéaire est définie comme ceci : f(x) = ax + b (sans rentrer dans les détailles et les informations de précisions).
L'objectif de ma fonction et de trouver la valeur de "y" pour une fonction définie par 2 points.
Pour cela, rien de bien compliqué, il suffit de trouver "a" et "b" avec les données qu'on nous donne. Soit :

  • a = (source_y-arrivee_y)/(source_x-arrivee_x)
  • b = source_y - source_x*a
Ce calcul n'est évidemment pas très compliqué à réaliser (et à trouver), cependant, je voulais ne pas avoir a répéter mes données source_x/y et arrivee_x/y à chaque utilisation.
J'ai donc choisi de retourner une fonction anonyme.

Implémentation
Pour avoir une fonction facilement utilisable, j'ai décidé d'utiliser les fonctions d'ordres supérieurs, soit des fonctions qui peuvent prendre des fonctions en argument et/ou retourner des fonctions. 
Un exemple d'utilisation serait:
  1. line_proc = equation_line(1,2,2,21)
  2. (0..150).each do | x |
  3.         put "(#{x}, #{line_proc.(x)}"
  4. end
(Afficher toutes les coordonnées de 0 à 15 pour une fonction linéaire passant de (1,2) à (2, 21))

Comment procéder (en utilisant la Curryfication) ? L'idée de la fonction est donc de retourner un Proc/une Lambda qui appliquerait la fonction trouvée (en calculant "a" et "b") à une valeur d'entrée.

Un problème de portée?
Je ne suis pas un spécialiste du Ruby et certains gourous pourront me contredire, mais j'ai vraiment du mal à percevoir la portée des variables, principalement dans le cas des "blocks". 
Par exemple : 
  1. a, b, c = 1, 2, 3
  2. l  = lambda{|x|a + b + c + x}
Est-ce qu'on peut utiliser a, b et c comme des variables globales (dans le cas présent) ?
Même si cet exemple est admissible, je trouve (et ce n'est que mon avis), que ce n'est pas très "joli".

Une autre idée aurait été de calculer les valeurs "a" et "b" dans la fonction que je retourne, le soucis c'est qu'un calcul qui ne devrait être exécuté qu'une seule fois devra être, pour chaque "y" demandé, recalculé. 
C'est pourquoi, la conclusion qui s'est naturellement offerte a moi est : "Passons "a" et "b" en argument !".
Le problème c'est qu'en dehors de ma fonction, je ne connais pas "a" et "b". 
La curryfication nous permettra donc de retourner une lambda a qui nous avons déjà passé 2 arguments, en l'occurrence "a" et "b". Voici une petite implémentation.
  1. def line_equation(sx, sy, cx, cy)
  2.        a = (sy-cy)/(sx-cx)
  3.        b = (sy - sx*a)
  4.        fun = lambda{|ap, bp, x|ap*x + bp}
  5.       return fun.curry.(a, b)

Conclusion
Je suis parfaitement d'accord pour dire que l'utilité de cet article est fortement discutable, cependant, je trouvais ça amusant de présenter une utilisation concrète de cette méthode.
De plus, elle permet d'être très fiable quant aux règles de portées de variables (domaine Ô combien flou pour les êtres limités comme moi dans la programmation) et aussi parce que c'est rigolo d'avoir du curry dans son code.

Merci de votre lecture. 
Raho.

mardi 22 mai 2012

Le Monkey Patching


Cet article est disponible en PDF


Résumé
Dans cet article, je vais tâcher de présenter une pratique de programmation douteuse appelée le « Monkey Patching », ou la « modification du singe » (aussi appelée le « Guérilla Patching ». Ainsi que de développer son intérêt dans la rédaction de scripts pour le logiciel RPG Maker. Sachez tout d'abord que je ne suis pas un grand adepte de ce genre de pratique, mais que dans les exemples présentés dans ce papier, le Monkey Patching me semble être une solution intéressante.



Introduction
Le terme Monkey Patching désigne la modification/l'extension de code source sans altérer la source originale (principalement dans les langages de programmations dynamiques). On peut considérer ça comme une extension de classe déjà déclarée (dans le cadre d'un langage orienté objets).
Concrètement, le Monkey Patching me permet d'ajouter/de greffer, de modifier des éléments d'une classe sans modifier le code original. Par exemple, je déclare une classe Voiture et un peu après, je lui ajoute une méthode rouler. Un autre exemple serait d'ajouter une méthode getFirst à ma classe String qui me retournerait le premier caractère d'une chaîne de texte. Certains langages permettent ce genre de pratique, je citerai non-exhaustivement Ruby, JavaScript ou encore Python. Cet article portera principalement sur Ruby.



Opinion sur le Monkey Patching
Bien que cela puisse paraître assez alléchant, le Monkey Patching pose énormément de problème de « raisonnement », en effet, nous sommes généralement habitués à lire notre code de manière linéaire, en abusant du Monkey Patching, lire un code (et donc, par extension, le raisonner), devient beaucoup plus complexe car nous ne savons jamais si le code que nous lisons est la « version finale ». Peut être qu'un patch a été rédigé plus loin, altérant un comportement défini. Donc, dans un projet classique, l'abus de ce genre de pratique peut entraîner une perte de temps conséquente dans la relecture du code.


Exception, les potentiels bienfaits du Monkey Patching
Dans certains cas, le Monkey Patching peut être une bénédiction. Comme exemple, je vais citer les logiciels RPG Maker édités par Enterbrain qui offrent (depuis leur version XP) une solution de programmation embarquée (utilisant le langage Ruby).


Un outil destiné aux non-programmeurs
RPG Maker est un jeu pour faire des jeux, dans ce sens, il n'est pas demandé à l'utilisateur de maîtriser le langage Ruby pou réaliser son jeu. La programmation n'est qu'un atout complémentaire pour pousser la personnalisation un peu plus loin. C'est donc naturellement qu'une nouvelle classe d'utilisateurs est née, les programmeurs, qui sans pour autant se lancer dans la création de jeux complets, produisent des patchs pour le logiciel en lui greffant/ en modifiant de nouvelles composantes.

Sans le Monkey Patching, l'ajout de ces patchs auraient demandés à l'utilisateur, une connaissance de Ruby (assez sommaire cela dit) et de modifier le code original du jeu. Grâce au Monkey Patching, il est possible d'ajouter ces patchs les uns à la suite des autres assurant une certaine compatibilité (dans la mesure du
possible).


Pourquoi Monkey Patcher plutôt que modifier le code original
Voici une petite liste des intérêts du Monkey Patching (dans le cadre de RPG Maker) non-exhaustive.

  • Possibilité de revenir au code d'origine facilement
  • Au moyen d'alias, assurer une compatibilité sensible
  • Réduire le nombre de modifications
  • Dans le cas de la lecture d'un script, comprendre ses modifications.

Je pense tout de même que le principal intérêt est de pouvoir facilement restaurer le code d'origine et de maximiser les inter-compatibilités.


Les alias, une des armes du Monkey Patching
Nous avons vu que nous pouvions « écraser » des méthodes, des attributs, mais les alias nous permettent de changer le nom d'une méthode. Cela peut être très pratique dans le cas ou je dois, par exemple, modifier une méthode pour lui greffer des actions. Je n'ai qu'a créer un alias de la méthode, réécrire la signature de la méthode, dans ma nouvelle méthode j'appelle l'alias et à la suite, j'écris mes modifications.
Malgré le côté très naïf de la chose, c'est un maximisant les alias faisables qu'on peut augmenter la compatibilité. Par exemple, admettons que j'écrive un patch pour ajouter à ma classe Game_Party un compteur de combat remportés. La solution « triviale » serait de modifier directement la classe. Mais admettons qu'un autre patch sorte pour ajouter une gestion des quêtes, si les 2 programmeurs n'utilisent pas les alias, les modifications d'un patch écraseront les modifications de l'autre. Alors que si l'un alias le constructeur de Game_Party, l'appelle dans son nouveau constructeur puis ajoute sa modification et que le suivant alias (une fois de plus) le constructeur de Game_Party l'appelle, et fait ses modifications, les 2 seront prises en comptes.


Conclusion
Je n'ai volontairement pas mis d'exemple de code car il s'agit plus d'exemples théoriques. Je maintiens que le Monkey Patching rend la lecture du code compliqué, mais dans le cas de patchs pour RPG Maker (par exemple) ils peuvent garantir une bonne compatibilité et une possibilité de revenir en arrière facilement !

Liens complémentaires (et probables sources)

Merci de votre lecture,
Michaël Spawn








jeudi 26 janvier 2012

Amusons-nous avec Pure Data

Les initiales du logiciels me parlent beaucoup...

Alors que je discutais de sujets divers avec Romain68 et il m'a montré une composition assez impressionnante avec PureData. Je dois avouer que le logiciel m'a plutôt amusé et ma curiosité a été piquée au vif.
Le logiciel est libre, donc me le procurer n'aura pas été une très lourde tâche (je vous invite à consulter leur site :) ). Et je me suis mis à lire leur documentation et à regarder quelques tutoriaux.
Comme j'ai trouvé l'expérience plutôt amusante, je me suis dit que j'allais rédiger un petit article sur les bases de PureData.
Cet article ne vous permettra pas de tout faire avec ce fabuleux logiciel mais je pense qu'il suffira à attiser la curiosité de certains. (Du moins je l'espère).


Qu'est ce que PureData?

Il est intéressant de se demander ce qu'est ce logiciel, car j'en parle avec beaucoup de "passion" mais je n'ai toujours pas encore expliqué de quoi il s'agissait.
PureData est un logiciel de programmation graphique (où vous saisissez vos "lignes de codes" de manière extrêmement interactive et graphique) utilisé pour la création multimédia (visuelle, audio) en temps réelle. Il a été inventé par Miller Puckette en 1988. Le logiciel est libre et fonctionne de manière assez modulaire. 
En effet, le logiciel peut être adapté à chaque utilisateur.

Un langage de programmation? Un logiciel?
PureData est un logiciel. Il ne s'agit pas d'un langage de programmation mais d'un environnement d'implémentation. Il est possible d'assembler des portions de codes pour créer des éléments très rapidement.
Le "langage" (car ces jeux d'instructions utilisables dans le logiciels respectent une certaine logique) permet de créer des applications procédurales avancées (proches de la programmation orienté Objets).


Exemple d'une application sonore sous Pure Data


Comme vous pouvez le voir ci-dessus, la structure d'une application PureData peut paraître complexe, cependant, bien que je doute qu'après cet article vous vous lancerez dans des applications si conséquentes (bien que vous verrez qu'en fait, elle est relativement simple).



Introduction avec le logiciel

Une fois que PureData installé (je vous conseille la version pd-extended), je vous invite à lancer le logiciel et à créer une nouvelle fenêtre (File > New ou CTRL+N). Voici un exemple de ce que vous devriez voir:


La fenêtre au premier plan sera celle sur laquelle nous placerons nos instructions. Celle en arrière plan correspond à une console qui nous affichera des "traces" de notre travail.
PureData interprète nos jeux d'instructions donc il ne faudra pas recompiler notre "programme" à chaque modification.

La fenêtre de travail
Sur la  fenêtre au premier plan (cf figure précédente), nous allons entrer nos instructions. Cette fenêtre possède 2 modes. Le premier mode est le mode "Actif" qui permet d’interpréter notre programme et le mode "Edition", qui nous permettra d'écrire notre programme.
Pour changer de mode, il existe 2 manières. La première consiste à passer par le menu situé dans l'en-tête de la fenêtre ( Edit -> Edit Mode) ou alors en utilisant le raccourcis CTRL+e (qui alterne de mode). Personnellement je n'utilise que le raccourcis parce que c'est tout de même plus commode :).
Pour commencer à travailler, mettons nous donc en mode Edit et commençons par une brève description des objets.


Survol sommaire des Objets
Dans PureData, nous serons amenés à utiliser des objets que nous lieront entre eux. Chaque objet/élément est composé d'entrées et de sorties. Les entrées sont les petits rectangles situés au dessus et les sorties sont les petits rectangles situés au dessous. Les sorties d'un objet peuvent être reliées aux entrées d'un autre objet. Exemple :

Exemple d'objets reliés


Nos applications seront structurées autours de cette manière de relier des objets. Nous allons donc survoler les objets que PureData met à notre disposition.
Cette liste d'objets se trouve dans l'onglet Puts. Nous les décrirons sommairement, mais vous verrez que tout deviendra beaucoup plus claire lorsque nous les mettrons en pratique avec des petits exemples.

  1. Objects, il s'agit du type que nous serons amené à utiliser le plus souvent. Il nous permettra de créer des instructions.
  2. Messages, il s'agit du type de données pour transmettre simplement des messages, chaines de textes voir même pour modifier certains attributs d'objets.
  3. Numbers, il s'agit simplement du type numérique, qui nous permettra d'entrer des données calculables et évaluables.
  4. Symbols, les symboles sont des valeurs qui n'ont pour valeur que leur nom. Pour le moment, nous ne nous en soucierons pas car nous ne les utilisons pas au début. (Les Symboles sont présent dans d'autres langages comme par exemple Lisp, Prolog, Erlang et Ruby).
  5. Comments, il ne s'agit que de blocs qui ne seront pas évalués mais très utiles pour structurer un code source.
Le reste des objets "putables" n'est pas encore décrit maintenant car il s'agit, pour la plupart de sucre pour créer certains objets rapidement. 
Maintenant que nous avons survolés nos "types primitifs", nous allons pouvoir nous lancer dans la programmation avec PureData. Notre premier exemple sera le drastiquement célèbre "Hello World".



Programmation avec PureData

Maintenant que nous avons survolé  le logiciel (de très haut, je vous l'accorde), nous allons pouvoir nous intéressé au développement de nos première applications. Bien qu'une application PureData puisse sembler complexe, vous verrez que ce langage respecte une logique très claire et qu'une fois quelques exercices pratiqués.

Notre première application: le Hello World
Cette première application n'est clairement pas très utile, cependant elle va nous permettre d'introduire les notions de relation entre les objets.
L'objectif est donc de créer une sortie dans la console du message "Hello World". La première chose à créer est donc un "Message" qui contient "Hello World". Placez-vous donc en mode édition et ajoutez à la scène un Message, (soit via l'onglet Put, soit au moyen de CTRL+2).
Lorsque ce message sera créé et aura pour valeur le texte à afficher en sortie. Nous allons créer un Objet, qui aura pour rôle d'effectuer la sortie. Cette commande s'appelle "print". Créez donc un Objet (Put ou CTRL+1) et inscrivez-y "print" (sans les guillemets). Maintenant il faudra relier la sortie de notre message à l'entrée de notre Objet. (Petit rappel, l'entrée est au dessus et la sortie en dessous. Pour créer un lien il faut cliquer sur le petits rectangles (un curseur en forme de cercle apparaît quand le coin est saisissable) et le glisser jusqu’à l'entrée d'un autre élément).
Une fois ceci fait, je fous invite à passer en mode actif (CTRL+E) et à cliquer sur notre message. Qu'est ce qui se passe dans la console ? Génial ! La console affiche bien "Hello World" !

Première application, done !

L'objet BANG
Nous allons un peu amélioré notre petite application au moyen d'un petit objet appelé Bang. Cet objet sera très très souvent utilisé dans nos applications PureData. L'objet Bang (qu'on peut créer en l'appelant directement au moyen du menu Put ou en créant un objet avec comme nom d'instruction "bng"). Ce petit objet qui ressemble a un rond inscrit dans un carré nous permettra, dans un premier temps d'activer une action au moyen du clique. Donc nous allons améliorer notre petite application pour qu'au clique d'un bang, elle affiche Hello et puis World.

Un clique, deux actions ! 

Le bang est un objet que nous seront habitué a manipuler très souvent et vous verrez qu'il peut aussi servir de marqueur pour savoir quand une opération a été exécutée. Bref un outil très utile.

PureData peut aussi être une calculatrice
Comme presque tout les outils de programmation, nous allons pouvoir nous servir de PureData comme un outil de calcul (qui nous sera très utile dans nos applications musicales...). Nous allons étudier ici comment utiliser PureData pour résoudre des calculs.
Qui dit calcul dit "Nombres", nous allons donc utiliser un objet Nombre. Cet objet nombre part toujours de zéro. Donc pour l'augmenter, il faudra utiliser la flèche et, en mode actif scroller de haut en bas pour modifier sa valeur. Pour entrer des opérations arithmétiques, ce n'est pas très confortable. Pour éviter ça, nous n'utiliseront un nombre que pour afficher le résultat. Pour les deux membres de notre opération, nous utiliserons des messages. Notre opérateur sera donc un simple objet avec pour valeur +; les plus perspicaces comprendront que si nous avions voulu faire x-y, nous aurions utilisé un objet - :).

Notre première opération

Ceux qui ont testé auront dut se rendre compte d'une chose. En appuyant une fois sur le Bang, le résultat obtenu est 85 et il faut appuyer une seconde fois pour obtenir le bon résultat. 
C'est parce que l'information doit être relayée. On pourrait donc considéré le premier appuis comme une forme de curryfication (mais j'exagère un tout petit peu là :) ). Nous allons donc voir comment éviter de devoir presser 2 fois sur le Bang (car même si pour faire du calcul ce n'est pas catastrophique, dans une application qui devra générer du son, ça pourrait être ennuyeux). Pour cela nous allons utiliser un nouvel objet.

L'objet Trigger
Un trigger est une sorte de pointeur d'argument, il nous permettra de considérer un groupe d'éléments comme une seule entrée. Il est typé en fonction du déclencheur (dans le cas notre addition, un Bang). Donc on est amené à créer un objet appellé "t" et on lui donne le nombre d'objets à déclencher en fonction d'une source. Dans notre cas, nous aurons donc "t b b" car nous avons deux éléments contrôlés par un Bang. Une fois cet objet créé, nous aurons donc 2 sorties sur notre objet que nous pourrons relié à nos 2 messages.

Voici donc un simple additionneur

Vous serez parfois amené à utiliser d'autres (pour des nombres, des pointers etc.).

Un peu de musique
Actuellement, nous n'avons fait que travailler avec des données numériques et textuelles. Comme je vous l'ai dit en début d'article, PureData est avant tout un outil de création multimédia, alors nous allons nous voir comment jouer des sons.
Pour nos premiers exercices sonores, nous allons travailler avec le format MIDI. (Qu'il faudra préalablement activer dans le menu Media > Midi Setting).
Jouer une note requiert certaines choses:
  1. Un contrôleur qui va définir la vitesse de la note et sa durée
  2. Une sortie pour jouer la note
  3. Un message qui contient l'identifiant de la note
Le contrôleur est un objet makenote qui prend 2 argument, le premier sera sa vitesse. Il fera office de relais à la sortie qui prend un "channel number", que nous positionnerons à 1. Et la note (numéro entre 0 et 127). Voici un petit exemple:


En appuyant sur le Bang (qui est fortement facultatif, appuyer sur le message suffit), vous devriez entendre un son.

Je pense que pour une brève introduction à PureData, nous allons nous arrêter là. Mon objectif n'étant pas de faire un cours complet sur ce très amusant outil, je terminerai mon petit descriptif ici.


Conclusion

Je termine donc ma petite présentation ici. J'espère que PureData aura éventuellement attiré votre attention et que, comme moi, vous avez trouvé ça amusant comme approche de la musique (et beaucoup moins indigeste que Reason dont la complexité de l'interface me donne chaque fois de l'urticaire).
Je n'ai volontairement pas été "trop" loin dans la présentation de cet outil pour éviter de présenter cette petite présentation comme un tutoriel. Cependant, il est possible que dans les jours/mois/semaines a venir, je publie des petites découvertes (sous forme d'article).

projets en perspective
Honnêtement, rien de concret en vue, PureData a vraiment été un prétexte pour discuter de choses (que je trouvais) amusantes. Je ne compte pas laisser tomber ce logiciel dans un tréfonds de ma mémoire pour continuer quelques expérimentations de mon côtés.

Découvrir PureData ailleurs
Je suis conscient que cet article n'était que introductif, donc voici une collection de liens qui pourraient servir à ceux qui ont été réellement intéressé par cette approche de la composition pour les jeunes GeeKs et un petit peu musiciens.

Le mot de la fin
Si vous avez des questions ou des remarques n'hésites pas à m'en faire part au moyen de l'interface de commentaires de Blogspot. Je tiens à préciser que je suis moi même novice n'ayant découvert ce logiciel seulement il y a quelques jours. 
Je vous souhaites une très bonne vie et merci de m'avoir lu.

Xavier "Nuki" Van de Woestyne

mardi 17 janvier 2012

La curryfication en Ruby


Cet article portera sur un point très particulier de Ruby (et traitera d'ailleurs d'un sujet qui n'appartient pas du tout à ce qu'il est indispensable de savoir en Ruby).

Introduction

La curryfication est une opération typique de la programmation fonctionnelle.
Dans cet article, nous allons aborder cette opération au moyen du langage de programmation Ruby, qui entre nous, n'est pas vraiment un langage où ce genre de procédé est important. Il s'agit surtout de curiosité.

 Cet article aura donc pour objectif de répondre à une certaine curiosité même si je doute que la curryfication prenne une place importante dans vos projets (du moins avec Ruby).

Définition & explication

Avant d'aborder l'aspect historique de la curryifcation, il est important de voir une chose. Dans un langage comme Haskell, toutes les fonctions ne prennent qu'un seul et unique argument/paramètre. Ceux qui ne programme pas en Haskell seront outrés ! Un seul argument c'est bien trop peu ! Ceux qui connaissent un petit peu Haskell (du moins de vue), diront que ces faux et ceux qui connaissent diront oui. En effet, en Haskell, les fonctions ne prennent qu'un seul argument et cet argument est une fonction qui prend elle même en unique argument le paramètre suivant et ainsi de suite.

Exemple
Voici une fonction f qui prend (normalement) 4 arguments. Comme elle est découpée ci-dessous, on peut facilement voir qu'elle prend 1 argument qui prend elle même un argument qui est une fonction etc. 

   f(g(h(i(x))))

Dans la programmation fonctionnelle, généralement, utiliser un espace entre 2 choses consiste à y appliquer une fonction, on peut donc considérer un espace comme un genre d'opérateur.
La curryfication est une opération qui permet donc de créer des fonctions pures (qui retournes toujours la même valeur pour les mêmes arguments).

Un peu d'Histoire
Je conclurai cette introduction en parlant de Moses Schönfinkel, l'inventeur de la curryfication et auteur d'un article sur la logique combinatoire, lui ayant attribué ce nom en référence au mathématicien Haskell Curry (partiellement contemporain à Moses Schönfinkel), que certains d'entre vous connaissent pour avoir poser les bases de la programmation fonctionnelle, le paradoxe de Curry (très amusant paradoxe permettant d'arriver à n'importe quelle conclusion à partir d'une phrase auto-référentielle et de quelques règles logiques, par exemple:
"Si cette phrase est vraie, alors le monstre du Memphrémagog existe.") ainsi que la correspondance Curry-Howard, un pont entre la théorie de la démonstration et l'informatique théorique qui a joué un rôle très important dans la logique.

Application & exemple d'utilisations

Tout ceci peut paraitre fort inutile mais nous allons voir des exemples très pratique d'utilisation. Exemples qui prouvent que la curryfication peut être un moyen très élégant pour résoudre certains cas très spécifique.
Prenons par exemple, une fonction dont le rôle est de multiplier 2 entiers entre eux (je suis d'accord que cet exemple n'est pas très original et je m'en excuse). Voici une solution OCaML:

 let multiplier x y = 
      x * y;;

Cette fonction est relativement simple et se contente de prendre 2 arguments et d'en retourner leur produit.
Cette petite fonction nous amène à une des utilisation les plus courante (pour ne pas dire la seule) de la curryfication, l'application partielle ! Posons le cas très simple où, possédant une fonction multiplier, j'ai envie d'écrire une fonction multiplierPar2. Rien de plus simple, il suffit de l'écrire, identique à la précédente, sauf quelle ne prend qu'un seul argument et qu'elle retourne x*2:

 let multiplier x  = 
      x * 2;;


Cependant, ce ne serait pas très intéressant !
Comme il a été expliqué dans l'introduction, une fonction peut prendre en argument une autre fonction et ainsi de suite. Donc il est possible d'appliquer partiellement nos arguments ! Exemple avec multiplier:

let multiplier x y = 
      x * y;;
let multiplierPar2
      multiplier 2;;

Je viens de faire une application partielle de mes argument. En effet "multiplier 2" va se contenter d'attendre les arguments manquants.
D'ailleurs, en testant "multiplierPar2 6" le résultat sera bel et bien 12.
Dans le cas des fonctions d'ordres supérieures (fonctions qui prennent d'autres fonctions en arguments et qui dans certains cas retournent d'autres fonctions), ce genre d'opérations est vraiment (en plus d'être élégant) puissant.
Avec un peu d'imagination, il serait envisageable de définir une fonction avec moins d'arguments que ce dont elle a besoin et d'utiliser la curryfication pour palier ce manque explicite.

Ce qu'il faut retenir
Tout ce petit blabla peut se résumer en une phrase... "En appellant une fonction avec trop peux de paramètres; on crée, en quelque sorte, des fonctions à la volée.".
Retenez aussi que la programmation fonctionnelle est plus adaptée que les autres paradigmes car beaucoup de langage fonctionnels admettent la curryfication nativement (comme Haskell).


La curryfication appliquée a Ruby

Appliquer des arguments de manière partielle à une fonction écrite en Ruby est envisageable sous plusieurs forme. La plus instinctive serait de jouer avec le passage d'argument sous forme de tableau:


def ma_methode(*arguments)

Ou encore en utilisant le passage d'arguments sous forme de Hash (Dictionnaire pour les Pythoneux)

def ma_methode(hash)
    argument1 = (hash[:argument1] || valeur_par_défaut)
    argument2 = (hash[:argument2] || valeur_par_défaut)
end

Rappelons que la forme x || y vérifie si le membre x et null et attribue si oui, x si non.
Ce genre de méthode est assez peu formelle et nous verrons qu'il existe une autre méthode.

La curryfication, c'est une fonction qui prend comme argument une autre fonction etc.
J'ai souvent répété cette phrase et elle devrait faire tiquer certaines personnes. En effet, quel objet/élément de Ruby est parfaitement adapté à cette situation? Oui, c'est la Lambda/Proc.
En effet, en lisant la description de la classe Proc on peut découvrir une méthode associée à Proc qui est curry, les Procs permettent donc nativement de gerer la curryfication. Exemple:


Comme on peut le voir, il est impossible d'appeler la fonction au moyen de call avec un seul argument (alors que notre lambda en requiert 2). Essayons avec notre fonction curry.


Cela fonctionne parfaitement, notre multiplier.curry retourne bien une nouvelle fonction qui attend un argument en plus. Essayons notre argumentation partielles en créant, sur base de multiplier, une fonction multiplier_par_2. (Curry se contente de retourner un Proc/Lambda avec comme nombre d'arguments les arguments manquants donc multiplier.curry.call(x) revient au même que multiplier.curry[x] voir même multiplier.curry.(x)). Voici la fonction multiplier_par_2 obtenue grâce à une curryfication de multiplier:


Et voila, voici donc un Proc curryfié. Dans le cadre des fonctions d'ordre supérieur, ça peut être très pratique. Cependant, je m'en sert rarement (mais je ne fais pas énormément de Ruby :) ).

Conclusion

Je conclus mon premier article sur FunkyWork ! Je dois avouer que son intérêt (pour Ruby) est assez limité mais je trouvais qu'il s'agissait tout de même d'un aspect amusant et intéressant à développer. 
Lié à certaines fonctions récursives, ou autre traitements spécifiques, la curryfication peut être un apport à la programmation Ruby. J'espère avoir au moins eu l'occasion de vous faire découvrir (ou redécouvrir) quelque chose d'amusant.
Merci beaucoup d'avoir lu cet article et je vous souhaites à tous, une très bonne année 2012 !

Pierre Ruyter.