Aller au contenu

Defun + Nombre d'arguments variable


Luna

Messages recommandés

Bonjour,

 

Petite question (sûrement idiote), mais je me demandais si l'on avait la possibilité de créer une fonction avec un nombre d'argument non défini/non fixe.

 

Par exemple la fonction '+ additionne l'ensemble des nombres spécifiés en argument, donc elle ne possède pas un nombre fixe d'argument comme la fonction 'car :

(+ 1 2 3 4 5 ... n)

 

J'ai trouvé ce post mais j'ai l'impression qu'il s'agit d'une version différente (à vrai dire je suis perdue entre les LISP, Visual LISP, ActiveX, Common LISP, ...) --"

J'ai testé ceci :

(defun test (a b &rest c)
 (if c
   a
   b
 )
)

commande:(test 0 1)
; erreur: nombre d'arguments insuffisants
commande:(test 0 1 T)
; erreur: nombre d'arguments insuffisants
commande:(test 0 1 T T)
0
commande:(test 0 1 T nil)
1
commande:(test 0 1 nil T)
0

Donc en clair, il ne reconnaît pas l'écriture &rest et le comprend comme un argument quelconque et non un keyword...

J'ai essayé également avec le keyword &optional mais même résultat...

Voici un extrait de la source de cette info (GNU Emacs Lisp Reference Manual) :

In a function description, the name of the function being described appears first. It is

followed on the same line by a list of argument names. These names are also used in the

body of the description, to stand for the values of the arguments.

The appearance of the keyword &optional in the argument list indicates that the subsequent arguments may be omitted (omitted arguments default to nil). Do not write

&optional when you call the function.

The keyword &rest (which must be followed by a single argument name) indicates that

any number of arguments can follow. The single argument name following &rest receives,

as its value, a list of all the remaining arguments passed to the function. Do not write

&rest when you call the function.

Here is a description of an imaginary function foo:

foo integer1 &optional integer2 &rest integers [Function]

The function foo subtracts integer1 from integer2, then adds all the rest of the

arguments to the result. If integer2 is not supplied, then the number 19 is used by

default.

(foo 1 5 3 9)

⇒ 16

(foo 5)

⇒ 14

Avez-vous déjà étudié cette question, est-ce seulement possible sur de la programmation basique avec AutoLISP 2018 ?

 

L'idée derrière cette question c'est pour éviter d'avoir à écrire deux fonctions quasi identiques ou bien d'avoir à me trimbaler une variable nil dans l'utilisation de cette fonction..

;; Définition deux deux fonctions quasi-identiques :
(defun func1 (arg1 arg2 / ...)

 [expr...]
 jsel

) ;;Renvoie un jeu de sélection

(defun func2 (arg1 arg2 / ...)

 [expr...]
 (princ rslt)

) ;;Renvoie le contenu du jeu de sélection

;;========================================================;;
;;Définition d'un argument prompteur
(defun func (arg1 arg2 display / ...)

 [expr...]
 (if display
   (princ rslt)
   jsel
 )

) ;; Donc à l'utilisation, il faudra obligatoirement écrire (func arg1 arg2 nil).

;;========================================================;;
;;Utilisation d'un argument optionnel
(defun func (arg1 arg2 &rest display / ...)

 [expr...]
 (if display
   (princ rslt)
   jsel
 )

) ;; Donc (func arg1 arg2) et (func arg1 arg2 nil) renverront le même résultat

 

Bisous,

Luna

Lien vers le commentaire
Partager sur d’autres sites

Salut,

 

Pas d'arguments optionnels en AutoLISP / Visual LISP.

Le seul moyen de contourner serait de passer comme argument une liste contenant les arguments. Mais je trouve ça lourdingue de tester la présence (et/ou le type) des arguments contenus dans la liste.

Gilles Chanteau - gileCAD -
Développements sur mesure pour AutoCAD
ADSK_Expert_Elite_Icon_S_Color_Blk_125.png

Lien vers le commentaire
Partager sur d’autres sites

Salut,

 

En effet j'avais déjà penser à cette solution mais en effet ça demande d'avoir un cond assez complexe pour prendre en compte toutes les possibilités par rapport aux arguments

Après dans mon cas, ça ne serait pas si complexe que ça puisque qu'il s'agit plutôt d'un argument optionnel et non un nombre d'argument indéfini..

 

Je trouve tout de même dommage que cela ne soit pas possible...Et dans ce cas, à quoi fait référence le document GNU Emacs Lisp Reference Manual ..? --"

 

Merci de ta réponse en tout cas ! :3

 

Bisous,

Luna

Lien vers le commentaire
Partager sur d’autres sites

Et dans ce cas, à quoi fait référence le document GNU Emacs Lisp Reference Manual ..? --"

À un autre dialecte LISP appelé Emacs LISP.

Depuis 1958 et l'invention du LISP nombre de dialectes ont vu le jour et certains sont toujours utilisés comme Common LISP, Emacs LISP, Scheme, Clojure et bien sûr AutoLISP.

Gilles Chanteau - gileCAD -
Développements sur mesure pour AutoCAD
ADSK_Expert_Elite_Icon_S_Color_Blk_125.png

Lien vers le commentaire
Partager sur d’autres sites

Avec ObjectARX ou .NET, on peut définir des fonctions LISP qui, comme les fonctions "natives" peuvent avoir des arguments optionnels.

Il y a quelques temps j'avais commis quelques fonctions LISP (CF LISP Extension sur cette page) dont une pour forcer les propriétés des calques par fenêtre.

La fonction accepte de 3 à 6 arguments, le troisième (couleur) peut être un entier (code ACI), une liste de 3 entiers (Rouge Vert Bleu) ou une liste de 2 chaînes pour les couleurs nommées (nom carnet)

 

Extarit de l'aide:

(gc-vplayeroverride fenetre calque couleur [typeLigne [epaisseurLigne [styleTrace]]])

 

Arguments

fenetre (ename)

Le nom d'entité de la fenêtre.

 

calque (string)

Le nom du calque.

 

couleur (int ou (red green blue) ou (colorName bookName))

L'index ou une liste de trois bytes (rouge vert bleu) ou une liste de deux chaînes (nom_de_la_couleur nom_du_carnet) pour la couleur à attribuer au calque (ou nil).

 

typeLigne (int) optionel

Le nom du type de ligne à attribuer au calque (ou nil).

 

epaisseurLigne (int) optionel

Un entier valide pour l'épaisseur de ligne à attribuer au calque (-3 = défaut, 0 = 0.00mm, 5 = 0.05mm, 15 = 0.15mm, 100 = 1.00mm, etc.).

 

styletrace (string) optionel

Le nom du style de tracé à attribuer au calque (uniquement STB).

 

 

 

Valeur retournée

T si l'opération s'est bien passée, nil sinon.

 

 

 

Exemple

(gc-vplayeroverride (car (entsel)) "Calque1" 40 nil 35)

 

La quasi totalité du code consiste à vérifier le nombre et le type des arguments (CF tous les : throw new *Exception;).

        // (gc-VpLayerOverride viewportEname layerName colorIndex [lineType [lineWeight [plotStyle]]])
       // (gc-VpLayerOverride viewportEname layerName RGBlist [lineType [lineWeight [plotStyle]]])
       // (gc-VpLayerOverride viewportEname layerName colorBookName [lineType [lineWeight [plotStyle]]])
       [LispFunction("gc-VpLayerOverride")]
       public TypedValue VpLayerOverride(ResultBuffer resbuf)
       {
           int i = 0;
           try
           {
               if (Application.Version.Major < 17 && Application.Version.Minor < 1)
               {
                   throw new LispException("only available for AutoCAD 2008 and later");
               }
               Document doc = AcAp.DocumentManager.MdiActiveDocument;
               Database db = doc.Database;
               ObjectId vpId;
               string layer;

               if (resbuf == null)
               {
                   throw new TooFewArgsException();
               }
               TypedValue[] args = resbuf.AsArray();
               if (args.Length < 3)
               {
                   throw new TooFewArgsException();
               }
               if (args.Length > 9)
               {
                   throw new TooManyArgsException();
               }

               if (args[i].TypeCode == (short)LispDataType.ObjectId)
                   vpId = (ObjectId)args[i++].Value;
               else
               {
                   throw new ArgumentTypeException("lentityp", args[i]);
               }

               if (args[i].TypeCode == (short)LispDataType.Text)
                   layer = (string)args[i++].Value;
               else
               {
                   throw new ArgumentTypeException("stringp", args[i]);
               }

               using (Transaction tr = db.TransactionManager.StartTransaction())
               {
                   Viewport vp = tr.GetObject(vpId, OpenMode.ForRead) as Viewport;
                   if (vp == null)
                   {
                       throw new LispException("bad entity type");
                   }
                   LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
                   if (!lt.Has(layer))
                   {
                       throw new LispException("unknown layer");
                   }
                   LayerTableRecord ltr = (LayerTableRecord)tr.GetObject(lt[layer], OpenMode.ForWrite);
                   LayerViewportProperties lvp = ltr.GetViewportOverrides(vpId);
                   if (args[i].TypeCode != (short)LispDataType.Nil)
                   {
                       if (args[i].TypeCode == (short)LispDataType.Int16)
                       {
                           short colorIndex = (short)args[i++].Value;
                           if (colorIndex < 0 || colorIndex > 256)
                           {
                               throw new LispException("incorrect color index");
                           }
                           switch (colorIndex)
                           {
                               case 0:
                                   lvp.Color = Color.FromColorIndex(ColorMethod.ByBlock, 0);
                                   break;
                               case 256:
                                   lvp.Color = Color.FromColorIndex(ColorMethod.ByLayer, 256);
                                   break;
                               default:
                                   lvp.Color = Color.FromColorIndex(ColorMethod.ByAci, colorIndex);
                                   break;
                           }
                       }
                       else if (args[i].TypeCode == (short)LispDataType.Point3d)
                       {
                           Point3d pt = (Point3d)args[i++].Value;
                           try
                           {
                               byte red = (byte)pt.X;
                               byte green = (byte)pt.Y;
                               byte blue = (byte)pt.Z;
                               lvp.Color = Color.FromRgb(red, green, blue);
                           }
                           catch
                           {
                               throw new LispException("incorrect RGB values");
                           }
                       }
                       else if (args[i].TypeCode == (short)LispDataType.ListBegin)
                       {
                           if (args[i + 1].TypeCode == (short)LispDataType.Text)
                           {
                               string colorName = (string)args[++i].Value;
                               if (args[++i].TypeCode != (short)LispDataType.Text)
                               {
                                   throw new ArgumentTypeException("stringp", args[i]);
                               }
                               string bookName = (string)args[i].Value;
                               try
                               {
                                   lvp.Color = Color.FromNames(colorName, bookName);
                                   i += 2;
                               }
                               catch
                               {
                                   throw new LispException("unknown color name");
                               }
                           }
                           else
                           {
                               throw new ArgumentTypeException("fixnump or stringp", args[i + 1]);
                           }
                       }
                       else
                       {
                           throw new ArgumentTypeException("fixnump or listp", args[i]);
                       }
                   }
                   if (args.Length > i + 3)
                   {
                       throw new TooManyArgsException();
                   }
                   if (args.Length > i)
                   {
                       if (args[i].TypeCode != (short)LispDataType.Nil)
                       {
                           if (args[i].TypeCode != (short)LispDataType.Text)
                           {
                               throw new ArgumentTypeException("stringp", args[i]);
                           }
                           string lType = (string)args[i++].Value;
                           LinetypeTable ltt = (LinetypeTable)tr.GetObject(db.LinetypeTableId, OpenMode.ForRead);
                           if (!ltt.Has(lType))
                           {
                               throw new LispException("unknown line type");
                           }
                           lvp.LinetypeObjectId = ltt[lType];
                       }
                       if (args.Length > i)
                       {
                           if (args[i].TypeCode != (short)LispDataType.Nil)
                           {
                               if (args[i].TypeCode != (short)LispDataType.Int16)
                               {
                                   throw new ArgumentTypeException("numberp", args[i]);
                               }
                               short lWeight = (short)args[i++].Value;
                               try
                               {
                                   lvp.LineWeight = (LineWeight)lWeight;
                               }
                               catch
                               {
                                   throw new LispException("incorrect line weight");
                               }
                           }
                           if (args.Length > i)
                           {
                               if (args[i].TypeCode != (short)LispDataType.Nil &&
                                   (short)AcAp.GetSystemVariable("pstylemode") == 0)
                               {
                                   if (args[i].TypeCode != (short)LispDataType.Text)
                                   {
                                       throw new ArgumentTypeException("stringp", args[i]);
                                   }
                                   string plotStyle = (string)args[i].Value;
                                   try
                                   {
                                       lvp.PlotStyleName = plotStyle;
                                   }
                                   catch
                                   {
                                       throw new LispException("unknown plot style");
                                   }
                               }
                           }
                       }
                   }
                   object lrc = AcAp.GetSystemVariable("layoutregenctl");
                   AcAp.SetSystemVariable("layoutregenctl", 0);
                   vp.UpgradeOpen();
                   vp.On = false;
                   vp.On = true;
                   AcAp.SetSystemVariable("layoutregenctl", lrc);
                   tr.Commit();
               }
               return new TypedValue((short)LispDataType.T_atom);

           }
           catch (LispException ex)
           {
               AcAp.ShowAlertDialog(ex.Message);
               throw;
           }
           catch (System.Exception ex)
           {
               AcAp.ShowAlertDialog(ex.Message);
               throw;
           }
       }

Gilles Chanteau - gileCAD -
Développements sur mesure pour AutoCAD
ADSK_Expert_Elite_Icon_S_Color_Blk_125.png

Lien vers le commentaire
Partager sur d’autres sites

Bonjour

En autolisp le nombre d'arguments des fonctions créées par défun est fixe, contrairement aux fonctions lisp elles-mêmes qui acceptent très souvent des arguments optionnels.

Il y a la possibilité de contourner avec la solution évoquée par (gile) en utilisant un seul paramètre qui est une liste.

Sinon, sachant que la possibilité de créer des arguments optionnels n'existe pas, je définis tous les arguments dans la liste et ceux qui peuvent être optionnels valent nil lorsqu'il ne faut pas en tenir compte et une valeur dans le cas contraire.

Un argument qui vaut nil c'est facile à vérifier.

Amicalement

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)

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é