Aller au contenu

Programmation fonctionnelle ou impérative


(gile)

Messages recommandés

Salut,

 

De ci de là on parle de paradigmes de programmation, j'ai donc pensé qu'il pouvait être intéressant de démarrer un sujet à propos des paradigmes de programmation supportés par AutoLISP / Visual LISP, à savoir la programmation fonctionnelle et la programmation impérative (procédurale).

 

Ces deux paradigmes correspondent à deux façons de penser, deux approches différentes pour résoudre un problème.

En gros, en programmation impérative, le code décrit en détail toutes les étapes de modifications des états des données nécessaires pour atteindre l'objectif.

En programmation fonctionnelle, pour éviter les changements d'état, on fait appel à des applications de fonctions (comme en mathématique) imbriquées dans un code plus déclaratif (on décrit ce qu'on veut obtenir plutôt que la façon de l'obtenir).

 

Je vais essayer d'illustrer ça avec un exemple simple : calculer la somme des carrés des nombres contenus dans une liste.

 

En programmation impérative, on modifie l'état d'une variable en lui affectant une nouvelle valeur à chaque itération dans une boucle.

L'algorithme décrit comment procéder :

- initialiser sum à 0

- pour chaque élément de la liste (x), affecter à sum sa valeur additionnée du carré de x

- renvoyer la valeur finale de sum

(defun sumOfSquares (lst / sum)
 (setq sum 0)
 (foreach x lst
   (setq sum (+ sum (* x x)))
 )
 sum
)

Avec la liste : (2 3 4)

initialisation : sum = 0

première itération, x = 2, sum = 0 + 2 * 2 = 4

seconde itération, x = 3, sum = 4 + 3 * 3 = 13

troisième itération, x = 4, sum = 13 + 4 * 4 = 29

 

En programmation fonctionnelle, on imbrique des appels de fonctions.

Premier exemple avec l'utilisation d'une fonction récursive (très courant en programmation fonctionnelle).

Un algorithme récursif tend à décrire l'intention plus que la méthode :

- ajouter le carré du premier élément à la somme des carrés des éléments suivants ou à 0 si la liste est vide

(defun sumOfSquares (lst)
 (if lst
   (+ (* (car lst) (car lst)) 
      (sumOfSquares (cdr lst))
   )
   0
 )
)

Avec une fonction récursive, les appels récursifs construisent une imbrication d'appels de fonctions jusqu'à ce que la condition d'arrêt soit atteinte (empilement), l'évaluation peut alors avoir lieu (dépilement).

Avec la liste (2 3 4)

(sumOfSquares '(2 3 4)

(+ 4 (sumOfSquares '(3 4)))

(+ 4 (+ 9 (sumOfSquares '(4))))

(+ 4 (+ 9 (+ 16 (sumOfSquares '()))))

(+ 4 (+ 9 (+ 16 0)))

29

 

Mais une des caractéristiques de la programmation fonctionnelle est de considérer les fonctions comme n'importe quelle autre type de donnée.

On peut lier un symbole à une fonction avec setq :

(setq f sqrt)

et utiliser le symbole comme la fonction :

(f 25)

renvoie 5.0.

Mais ça permet surtout d'utiliser une fonction comme argument d'une autre fonction dans ce qu'on appelle les fonctions d'ordre supérieur (apply, mapcar, vl-some, vl-remove-if, ...)

 

Second exemple avec des fonctions d'ordre supérieur

Ce type de fonction permet d'écrire du code de manière déclarative.

L'algorithme se réduit une déclaration de ce que l'on souhaite obtenir:

- faire la somme des nombres de la liste mis au carrés

(defun sumOfSquares (lst)
 (apply '+ (mapcar '(lambda (x) (* x x)) lst))
)

La fonction apply applique la fonction qui lui est passé en premier argument (ici, +) aux arguments contenus dans la liste qui lui est passée en second argument (ici, la liste de nombres retournées par (mapcar ...)).

La fonction mapcar retourne une liste qui est le résultat de l'application de la fonction qui lui est passée en premier argument à tous les éléments de la liste qui lui est passée en second argument.

La fonction passée en argument à mapcar est une fonction lambda, encore une spécificité de la programmation fonctionnelle.

(lambda (x) (* x x))

renvoie le carré du nombre qui lui est passé an argument

Avec la liste (2 3 4)

(mapcar '(lambda (x) (* x x)) '(2 3 4))

renvoie (4 9 16)

(apply '+ '(4 9 16)))

renvoie le résultat de l'évaluation de (+ 4 9 16), soit 29

 

 

Autres exemples

 

Supprimer tous les doublons d'une liste (1 2 1 3 2 3) => (1 2 3).

Impératif :

(defun distinct	(lst / res)
 (while lst
   (setq res (cons (car lst) res)
  lst (vl-remove (car lst) lst)
   )
 )
 (reverse res)
)

Fonctionnel (récursion) :

(defun distinct	(lst)
 (if lst
   (cons (car lst) (distinct (vl-remove (car lst) lst)))
 )
)

 

 

Transposer une matrice ((1 2 3) (4 5 6)) => ((1 4) (2 5) (3 6))

Impératif :

(defun transpose (mat / i j row res)
 (repeat (setq i (length (car mat)))
   (setq i (1- i)
  row nil
   )
   (repeat (setq j (length mat))
     (setq j (1- j)
    row (cons (nth i (nth j mat)) row)
     )
   )
   (setq res (cons row res))
 )
)

 

Fonctionnel (un joyaux du LISP à mon sens) :

(defun transpose (mat) 
 (apply 'mapcar (cons 'list mat))
)

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

 

Merci pour ce joli cadeau de Pâques

 

vais pouvoir combler mes énormes lacunes dans le domaine des paradigmes.

 

j'y réfléchis même pas quand j'élabore un algorithme.

 

en fait je mélange les 2 sans m'en apercevoir.

 

doit faire du procédural fonctionnel et/ou l'inverse. :rolleyes:

Lien vers le commentaire
Partager sur d’autres sites

Les deux paradigmes sont supportés, on peut donc faire les deux quand on a le choix, c'est une question de préférence.

 

Ceci dit on n'a pas toujours le choix, on utilise généralement AutoLISP pour modifier l'état d'un dessin AutoCAD et ça c'est typiquement impératif. Toutes les fonctions qui retournent toujours nil comme command, prompt, etc. sont typiquement procédurales. D'un autre côté, pour traiter une structure en arborescence, la récursion est incontournable.

 

En fait on a le choix dans le traitement des données, notamment des nombres et des listes.

Le paradigme fonctionnel permet en général du code plus concis et parfois plus facile à lire (déclaratif) à condition de connaître les fonctions utilisées. Il permet aussi d'écrire du code plus robuste et facile à maintenir (même si ça s'applique moins à AutoLISP qu'à des langages plus "riches").

 

Après je pense qu'il s'agit vraiment de deux façons de penser/raisonner différentes (qui ne sont pas incompatibles) et j'ai pu noter que ceux qui étaient ou devenaient à l'aise avec le paradigme fonctionnel étaient du coup plus à l'aise avec AutoLISP en général.

Autrement dit, la compréhension des fonctions d'ordre supérieur (mapcar), des fonctions anonymes (lambda) et de la récursivité est, à mon avis, une étape majeure dans l'apprentissage du LISP qui permet une compréhension plus intime du plus ancien langage fonctionnel.

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Coucou

 

Je serais donc impératif ... mon père étant chauve je n'ai pas un père à tifs pour autant,

Blague (mauvaise) à part, c'est très intéressant ce que tu expliques (comme toujours)

Et je vais faire mon possible pour ingurgiter ces façons de faire

Mes "routines", je te laisse le mot "programme", devenant de plus en plus compliquées (toujours pour mon niveau)

Je suis certain que dans bien des cas faire une sous-routine fera du bien dans mon impérativité en tentant une dose de "fonctionnelle" voire de récursion

Encore merci

 

Amicalement

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

 

Pour le clin d'œil :rolleyes:

(defun sumOfSquares (lst)
 (apply '+ (mapcar '* lst lst))
)

 

Avec une très forte préférence pour la programmation fonctionnelle en ce qui me concerne, et un grand merci à (gile) pour le temps que tu prend à la rédaction ce type de sujet

 

Amicalement Bruno

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Coucou

 

Il y a deux poids deux mesures clairement

  • ceux qui parlent anglais et ceux qui le baragouinent
  • ceux qui font des rallyes et ceux qui se déplacent en voiture
  • les impératifs et les fonctionnels

Certes,(Gile) n'a pas voulu établir de hiérarchie mais de la part des baragouineurs (les impératifs) il faut reconnaitre que les fonctionnels impressionnent.

Respect.

 

Amicalement

Lien vers le commentaire
Partager sur d’autres sites

Hello

Je soutiens le vieux Diplodocus Didier qui va impérativement écraser les Jeunes "fonctionnels" ?!

Bye, lecrabe (Decapodiquement votre Devoue Vieux Dinosaure)

 

PS1: nous écraserons humoristiquement !

 

PS2: en fait on a besoin des jeunes pour payer notre retraite !

Autodesk Expert Elite Team

Lien vers le commentaire
Partager sur d’autres sites

Coucou

 

Loin de moi l'idée de vouloir écraser qui que ce soit, c'est pas le genre de la maison, même si des fois fois je suis "cash" dans ce que je dis et de la façon que je le dis mais pas pour écraser.

 

J'ai appris seul dans ma chambre, pas à pas, en remarquant que si je faisais (setq zz (getpoint... une triplette de coordonnées se retrouvait dans la variable zz

Je vous parle des années 90 ! et j'ai stagné pendant très très longtemps

Pendant ce temps-là il fallait continuer à travailler et le lisp c'était le soir et la nuit

Quand j'arrivais à faire quelque chose, j'avoue que je restais au point où ça fonctionnait

Je n'ai pas cherché à faire mieux et du coup aujourd'hui je me trouve à la traîne des autres qui ont grandi dans les règles

Et dire que je veux "apprendre" aux autres avec mon site perso

Il y a de la remise en question dans l'air...

 

Amicalement

Lien vers le commentaire
Partager sur d’autres sites

[...]il faut reconnaitre que les fonctionnels impressionnent.

Tu m'étonnes... Ça reste encore de la science-fiction pour moi... ;)

 

Et dire que je veux "apprendre" aux autres avec mon site perso

Il y a de la remise en question dans l'air...

N'abandonne surtout pas, maintenant qu'il devient un reflex pour certains (et en devenir pour d'autres)...

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Il ne faut pas s'affoler et surtout pas désespérer.

 

À part de très rares exceptions pour qui la programmation fonctionnelle semble innée (comme VDH-Bruno qui ne cesse de m’impressionner), quand on commence à programmer c'est en général de façon impérative, a fortiori quand on cherche à automatiser ce qu'on fait dans AutoCAD de façon procédurale. Qu'on soit passé par les macros, les scripts ou le VBA AutoCAD, on commence par enchaîner les commandes, éventuellement dans des boucles.

 

Dans tous les cas, la programmation d'AutoCAD sera toujours essentiellement procédurale. comme dit plus haut, la programmation fonctionnelle ne s'applique qu'à certains traitements de données. Et, à de très rares exceptions près, ces traitements peuvent très bien être fait (et être très bien faits) de manière impérative.

 

À mon sens l'intérêt de la programmation fonctionnelle avec AutoLISP est d'une part didactique ou pédagogique*, d'autre part pratique.

 

Le côté didactique est essentiellement représenté par la récursivité en ce sens que c'est une façon de raisonner différente de la pensée séquentielle/linéaire et qu'elle est fondamentale dans l'implantation du LISP.

Une expression LISP se définit récursivement comme étant : soit un atome ; soit une liste d'expressions LISP.

Une liste chainée (seule structure de données utilisé par AutoLISP) est en fait une structure récursive :

(list 1 2 3) est un raccourci pour (cons 1 (cons 2 (cons 3 (cons nil)))).

La compréhension de la récursivité peut donc être vue comme une ouverture d'esprit, un prise conscience de la façon dont le LISP fonctionne.

 

Dans la pratique, à part produire du code souvent plus concis et plus élégant, la récursivité est généralement moins efficiente en terme de performance et limitée par la "taille de la pile".

Par contre, les fonctions d'ordre supérieur (apply, mapcar, vl-sort, vl-some, vl-remove-if, etc.) ont, à mon avis, un grand intérêt pratique en permettant d'écrire un code à la fois plus concis et plus facile à comprendre en ce sens qu'il décrit directement l'objectif à atteindre plutôt que le processus à suivre pour y arriver.

 

 

* avant de revenir un peu sur le devant de la scène ces dernières années la programmation fonctionnelle intéressait surtout le milieu éducatif.

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Coucou

 

Tu as l'art et la manière de remonter le moral des gens, tu es prêt à passer dans le monde des RH ou de la politique

"monsieur, bien que je pense que vous êtes un digne représentant des gens de niveau zéro, vous avez toute votre place dans notre société avec vos qualités intrinsèques"

Je blague, tu l'as compris et je te souhaite de toujours rester au plus loin possible de cette race de gens (qui, eux ne savent pas blaguer)

 

Donc, ça vient de là, en fait ce que je fais comme "programmation" tient au départ presque du "traitement par lots" des fichiers batch, une opération après l'autre.

Ce n'est qu'ensuite que je cherche à enjoliver, à parfaire, à polir mes routines.

D'ailleurs depuis que tu as lancé ces explications j'ai déjà compris certains trucs que je dois encore travailler, mais il me semble avoir compris, et c'est une (petite) fierté pour moi.

Un grand MERCI à Toi

 

Amicalement

Lien vers le commentaire
Partager sur d’autres sites

En ce moment, je n'en finis pas d'explorer cadxp. Je vais donner une formation à autolisp puis Vlisp pour la première fois et travaille d'arrache pied.

J'ai de la documentation merveilleuse et à profusion et même en Français du plus récent ((gile) aux plus anciens, MENU ou TESTE et AGBETIAFA, noms d'auteurs d'anciens bouquins).

 

Des idées aux kilomètres et cette grande, très grande base de données un peu confuse tout de même qu'est cadxp. On y compte par exemple, des dizaines de challenges, parfois même certains drôlement intéressants et nullement titrés comme tels car de simples sujets sont devenus challenges.

Alors je suis tenté de passer des heures ici. Ce que j'ai fait, profitant d'avoir avancé dans mes travaux.

 

Des dizaines de posts de (gile) et d'autres non moins fameux qui font le point sur tel ou tel aspect de la prog lisp comme celui-ci.

Je suis des tas de liens y compris des très anciens pour trouver des exercices et de l'inspiration mais je croule, il faut le dire. Je m'éclate aussi.

 

Ce message comme bien d'autres, mériterait un petit référencement tel que je le mène un peu en dilettante.

Si certains ont déjà commencé ce genre de démarche, faites-moi suivre vos collections de liens.

 

Je pense au hasard et dans le désordre à des tas de thèmes :

 

  • registres
  • challenges
  • vlax-curve
  • chargement
  • grread
  • collections et blocs
  • tabloblo
  • pline_block
  • sélection
  • culture lisp
  • dcl
  • gestion d'erreur
  • scu et objets

 

Je n'ai pas vérifié mais cela n'a jamais été fait de tenir une liste de liens internes dans un message en tête (épinglé), une sorte de sommaire capable de faire remonter utilement le temps.

Je serais prêt à référencer des sujets. Avec un peu d'aide.

Je sais tout lire et m'entraine à tout expliquer du moindre code.

Donc je pourrais, sans tout tester, pointer, avec l'aide des concernés, les bonnes adresses, ainsi que les sujets aux liens morts, voire à réparer. Il y a eu des applis maintes fois transformées ou des sujets souvent revenus.

?

Je serais content, non pas que cela soit rangé, c'est impossible mais de trouver de robustes sommaires.

Bureau d'études dessin.

Spécialiste Escaliers

Développement - Formation

 

./__\.
(.°=°.)
Lien vers le commentaire
Partager sur d’autres sites

Coucou

 

On sort du sujet à cette occasion mais figure-toi que tu n'es pas le seul dans cette démarche

Le souci, c'est qu'il y a pas mal de messages dont on a perdu la trace car les liens sont morts et je n'ai pas encore trouvé la façon de les faire revivre.

L'aide de CadMin ne serait pas de trop mais son silence quand on lui demande quoi que ce soit n'aide pas le dossier.

Sans vouloir squizzer CadXP j'ai l'intention de faire une rubrique sur mon site qui reprend les différentes façons de traiter le même souci grâce à ces exemples archéologiques.

 

Je pense aussi que tu devrais créer un nouveau sujet pour ça et laisser la discussion sur les programmations impératives et fonctionnelles en dehors de cette affaire, je déplacerai ma réponse quand je verrai ce sujet

 

Amicalement

Lien vers le commentaire
Partager sur d’autres sites

Je pense que je tenterai au moins de faire un sommaire des challenges.

Car justement, on s'y ballade beaucoup entre l'itératif, le récursif et le fonctionnel, si tu veux.

 

Mais cher Didier, nous pouvons très bien travailler ici, entre plusieurs modos, et placer tous les liens chez toi à tout moment, en doublon ou pas. Alors sache bien qu'un tel travail n'appartiendra à personne donc à tous.

Bureau d'études dessin.

Spécialiste Escaliers

Développement - Formation

 

./__\.
(.°=°.)
Lien vers le commentaire
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer. Politique de confidentialité