Aller au contenu

Messages recommandés

Posté(e)

Par contre, je vient de faire un benchmark avec lambda

 

Elapsed milliseconds / relative speed for 8192 iteration(s):

 

((LAMBDA (S) (VL-LIST->STRING (MAPCA...).....1139 / 1.36 <fastest>

((QUOTE ((S) (VL-LIST->STRING (MAPCA...).....1545 / 1 <slowest>

Posté(e)

Je vais essayer une petite explication.

 

En des temps que seuls certains dinosaures ont connu, avant l'optimisation d'AutoLISP avec Visual LISP (AutoCAD 2000) les fonctions LISP étaient définies comme des listes.

De cette époque reculée, il nous reste une trace : la fonction defun-q.

L'aide nous dit que cette fonction existe essentiellement pour des problèmes de compatitbilité avec les anciennes versions d'AutoLISP et recommande de lui préferer defun.

 

Si on définit une fonction avec defun, on crée un objet de type USUBR :

_$ (defun sqr (x) (* x x ))
SQR
_$ (type sqr)
USUBR
_$ sqr
#<USUBR @000001d743bd8188 SQR>

Si on fait la même chose avec defun-q, on crée une liste :

_$ (defun-q sqr (x) (* x x ))
SQR
_$ (type sqr)
LIST
_$ sqr
((X) (* X X))

Or on sait aisément construire cette liste sans utiliser defun-q :

_$ (list '(x) '(* x x))
((X) (* X X))

Ou, plus simplement :

_$ '((x) (* x x))
((X) (* X X))

Ce qui veut dire qu'une liste 'quotée' contenant la structure d'une fonction, est une fonction LISP.

 

On peut affecter cette liste à un symbole avec setq :

(setq sqr '((x) (* x x)))

et utiliser le symbole comme une fonction :

_$(sqr 3)
9

 

On peut aussi utiliser directement la liste (comme on le ferait avec un lambda) :

_$ ('((x) (* x x)) 3)
9

 

On peut utiliser ce symbole avec les fonctions d'ordre supérieur :

_$ (mapcar 'sqr '(1 2 3))
(1 4 9)

mais aussi directement la liste quotée (comme on le ferait avec une expression lambda), et comme les fonctions passées comme argument aux fonctions d'ordre supérieur doivent être 'quotée', il faut doubler l'apostrophe (attention, il semble que ce ne soit pas le cas avec l'AutoLISP de BricsCAD) :

_$ (mapcar ''((x) (* x x)) '(1 2 3))
(1 4 9)

 

Les différences de performance notée par Fraid sont dues au fait que defun comme lambda génèrent des objets de type USUBR qui sont optimisés par rapport aux listes qui sont ré-interprétées à chaque exécution.

 

En conclusion, le seul intérêt (excepté le fait d'écrire du code plus 'crypté') de defun-q (ou des listes équivalentes) est la possibilité de redéfinir la fonction en modifiant la liste (à suivre...).

 

PS : j'ai découvert ça assez récemment avec ce sujet sur TheSwamp dans lequel, chose exceptionnelle, Elpanov Evgeniy pose une question.

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

Posté(e)

La possibilité de redéfinir une fonction définie avec defun-q est généralement illustré avec la fonction S::STARTUP.

On trouve aussi une ingénieuse façon d'utiliser ce comportement dans la fonction ai_sysvar définie dans .\Support\fr-fr\acad20XXdoc.lsp du répertoire d'installation.

 

On peut prendre un exemple simple avec une fonction qui génère un entier incrémenté à chaque appel sans utiliser aucune donnée extérieure.

(setq f	'((/ i)
  (setq i 1)
  (setq f (cons '(/ i) (cons (list 'setq 'i (+ i 1)) (cddr f))))
  i
 )
)

 

_$ f
((/ I) (SETQ I 1) (SETQ F (CONS (QUOTE (/ I)) (CONS (LIST (QUOTE SETQ) (QUOTE I) (+ I 1)) (CDDR F)))) I)
_$ (f)
1
_$ f
((/ I) (SETQ I 2) (SETQ F (CONS (QUOTE (/ I)) (CONS (LIST (QUOTE SETQ) (QUOTE I) (+ I 1)) (CDDR F)))) I)
_$ (f)
2
_$ f
((/ I) (SETQ I 3) (SETQ F (CONS (QUOTE (/ I)) (CONS (LIST (QUOTE SETQ) (QUOTE I) (+ I 1)) (CDDR F)))) I)
_$ (f)
3

 

Et Bonne Année quand même....

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

Posté(e)

@Fraid,

 

un benchmark plus significatif qui compare la même fonction définie avec une liste, defun-q, lambda et defun.

 

;; liste
(setq f1 '((x) (* x x)))

;; defun-q
(defun-q f2 (x) (* x x))

;; lambda
(setq f3 (lambda (x) (* x x)))

;; defun
(defun f4 (x) (* x x))

 

_$ (benchmark '((f1 4) (f2 4) (f3 4) (f4 4)))
Benchmarking ..................Elapsed milliseconds / relative speed for 32768 iteration(s):

   (F3 4).....1703 / 3.00 <fastest>
   (F4 4).....1703 / 3.00
   (F2 4).....5093 / 1.00
   (F1 4).....5109 / 1.00 <slowest>

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

Posté(e)

Bonne année à toi aussi wink.gif

Steven________________________________________

Pour le taf; Windows (et ses emmerdes) sinon pas d'AutoCAD.

Pour le perso Linux Mint et pas de problèmes. Mais pas d'AutoCAD.

En rêve; AutoCAD sous Linux.

Posté(e)

Bonne année et meilleurs vœux, prennez soin de vous.

 

Sinon pour l'exemple et faire écho au sujet ouvert par (gile)

('((rec l) (rec l))
 '((l) (if l (strcat (chr (car l)) (rec (cdr l))) ""))
 '(82	 233  233  99	114  105  116  117  114	 101  32   100	101
   32	 118  108  45	108  105  115  116  45	 62   115  116	114
   105	 110  103  32	97   117  32   109  111	 121  101  110	32
   100	 39   117  110	101  32	  112  115  101	 117  100  111	32
   102	 111  110  99	116  105  111  110  32	 97   110  111	110
   121	 109  101  32	114  233  99   117  114	 115  105  118	101
   32	 58   41
  )
)

A+ Bruno

Apprendre => Prendre => Rendre

Posté(e)

Bonne année, un 20/20 à tous !

 

Amic'allemand

Vincent

C'est au pied du mur que l'on reconnaît le maçon ! (Anonyme)

C’est en restant au pied du mur qu’on ne voit que le mur (Anonyme aussi)

  • 2 semaines après...
Posté(e)

Re,

 

En conclusion, le seul intérêt (excepté le fait d'écrire du code plus 'crypté') de defun-q (ou des listes équivalentes) est la possibilité de redéfinir la fonction en modifiant la liste (à suivre...).

Même si l’intérêt de tout ceci n’est pas fondamental, j’espérais réussir à enrichir un peu ce fil..

 

Mais par manque de disponibilité, je ne pense pas développer plus ma réponse, malgré tout je propose en vrac quelques réflexions que je m’étais déjà fait sur cette question:

 

Parfois la possibilité de définir des fonctions sous forme de liste autre qu’avec defun, defun-q et lambda permet de façon ludique, d’écrire un code plus concis (et pas que plus crypté).

 

A titre d’exemple la revisite d’un ancien challenge, sur TheSwamp où des solutions pour porter la fonction let dans AutoLISP sont proposées.

 

Code que l’on pourrait facilement réécrire comme ceci

(defun let (bindings body) (apply '(list (mapcar 'car bindings) body) (mapcar 'cadr bindings)))

_$ (let '((x 3) (y 10)) '(+ x 10 (* x y)))
43

 

On peut noter la possibilité d’étendre la fonction vl-propagate aux fonctions, en les définissant en setq.

_$ (vl-propagate 'let) ;Fonction définie avec defun ou defun-q
; erreur: Visual LISP: Objet d'importation/exportation entre documents non conforme #<USUBR @14c23d48 LET>

_$ (setq let '((bindings body) (apply '(list (mapcar 'car bindings) body) (mapcar 'cadr bindings))))
((BINDINGS BODY) (APPLY (QUOTE (LIST (MAPCAR (QUOTE CAR) BINDINGS) BODY)) (MAPCAR (QUOTE CADR) BINDINGS)))
_$ (vl-propagate 'let)
((BINDINGS BODY) (APPLY (QUOTE (LIST (MAPCAR (QUOTE CAR) BINDINGS) BODY)) (MAPCAR (QUOTE CADR) BINDINGS)))

 

A+

Apprendre => Prendre => Rendre

  • 2 ans après...
Posté(e)
Le 16/01/2020 à 12:52, VDH-Bruno a dit :

 

Code que l’on pourrait facilement réécrire comme ceci

 

(defun let (bindings body) (apply '(list (mapcar 'car bindings) body) (mapcar 'cadr bindings)))

je retombe par hasard sur ce vieux sujet et je constate que cette définition ne permet pas de passer des expressions à évaluer dans les "bindings".

(let
  '((a (/ pi 3)))
  '(let
    '((sinus (sin a)) (cosinus (cos a)))
    '(list a sinus cosinus)
   )
)

renvoie :

((/ PI 3) (SIN A) (COS A))

 

C'est dû à l'utilisation de (apply ...) au lieu de (eval (cons ...))

(defun let (bindings body)
  (eval
    (cons
      '(list (mapcar 'car bindings) body)
      (mapcar 'cadr bindings)
    )
  )
)

et maintenant,

(let
  '((a (/ pi 3)))
  '(let
    '((sinus (sin a)) (cosinus (cos a)))
    '(list a sinus cosinus)
   )
)

renvoie :

(1.0472 0.866025 0.5)

 

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

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é