Can you supply a function as an argument to a custom defined function?

Can you supply a function as an argument to a custom defined function?

Anonymous
Not applicable
949 Views
8 Replies
Message 1 of 9

Can you supply a function as an argument to a custom defined function?

Anonymous
Not applicable

Teaching myself lisp and sometimes I find myself writing 2 or more lines of the same code with the only difference being a function name.  Is it possible to supply a function name as an argument to another function?

 

Ex: If I write 2 functions, "Xval" that returns the X value and "Yval" that returns the Y value, is it possible to supply "Xval" or "Yval" as an argument to another function whose operation uses either the X or Y value depending on the circumstances?

 

Thanks,

0 Likes
Accepted solutions (2)
950 Views
8 Replies
Replies (8)
Message 2 of 9

Kent1Cooper
Consultant
Consultant

Yes.  Something like:

 

 

(defun Xval (pt)
  (car pt)
)

(defun Yval (pt)
  (cadr pt)
)

Then [the same could probably be done in a more direct way, but just as one example of variable circumstances]:

 

(defun C:Whatever (/ testpt which)
  (setq testpt (getpoint "\nPick a point: "))
  (initget "X Y")
  (setq which (getkword "\nLine from perpendicular axis in which direction [X/Y]? "))
  (command "_.line"
    (list
      (if (= which "X") 0 (Xval testpt))
      (if (= which "X") (Yval testpt) 0)
      0
    ); list
    testpt ""
  ); command
); defun

 Very basic, doesn't guard against running Object Snap, etc., etc., but you get the idea.

 

EDIT:  Or, you could skip the middleman of 'pt' as an argument in the Xval/Yval functions, if you always name the point variable in any larger functions that use those in the same way:

 

(defun Xval ()
  (car pt)
)

(defun Yval ()
  (cadr pt)
)

 

(defun C:Whatever (/ pt which)
  (setq pt (getpoint "\nPick a point: "))
  (initget "X Y")
  (setq which (getkword "\nLine from perpendicular axis in which direction [X/Y]? "))
  (command "_.line"
    (list
      (if (= which "X") 0 (Xval))
      (if (= which "X") (Yval) 0)
      0
    ); list
    pt ""
  ); command
); defun
Kent Cooper, AIA
0 Likes
Message 3 of 9

Anonymous
Not applicable

Sorry, what I should have asked was: Can you supply a function name as an argument?

 

Specifically I'm trying to write a program that automatically applies ordinate dimensions and I need it to properly handle multiple lines with the same dimension. What I want to do is something like:

 

 

(setq VLM (multlines VL 'Xval)) 
(setq HLM (multlines HL 'Yval))

(defun MULTLINES (SS XorY) (setq SSI (sslength SS) SSI2 SSI) (while (not (minusp (setq SSI (1- SSI)))) (setq ENT1 (ssname SS SSI)) (while (not (minusp (setq SSI2 (1- SSI2)))) (setq ENT2 (ssname SS SSI2)) (if (and (= (XorY ENT1 10) (XorY ENT2 10)) (/= SSI SSI2)) (ssadd (ssname SS SSI) SSM) ) ) )
(setq SSM SSM) )

Where HL & VL are selection sets of horizontal & vertical lines, and the code should find the horizontal lines with equal Y values and vertical lines with equal X values and put them into separate selection sets containing only the lines that have multiple of the same Y or X values.

 

Thanks,

 

0 Likes
Message 4 of 9

dbroad
Mentor
Mentor
Accepted solution

Without getting into the multiple errors in your code, the answer to your question is yes, you can pass a name and use it as a function.  The apply, mapcar, and eval functions can be useful for this.

 

Example:

 

(defun foo (elist fun key)
  (apply fun (list(cdr(assoc key elist))))
)

(defun xval (pt)
  (car pt))

(setq myline (entget(car(entsel))));;select a line for example

;;use the function

(foo myline 'xval 10)
;;should return the xvalue of the beginning of the line

 

Architect, Registered NC, VA, SC, & GA.
0 Likes
Message 5 of 9

Anonymous
Not applicable

Well can we get into what you would consider errors in my code? I'm a mechanical designer not a programmer, but I'm trying to get better. And I changed a few things around before I posted it, but I had the same basic structure testing X first, and then a duplicate structure testing Y and it worked fine, I was just hoping to condense it.

 

Also, when I tested the code I posted it gets to the IF statement and then throws "EGT Error: bad function: Xvalno function definition: GRERR_" but the program uses the Xval function before reaching the APPLYDIMS function. Have any insight on that?

0 Likes
Message 6 of 9

dbroad
Mentor
Mentor

Thanks for sharing that.  I am an architect.  Your function has a nested while loop which looks puzzling and it looks like you are trying to compare points without getting any entity data from the ename.  Of course you didn't actually post the code for the xdir or ydir so you could be doing all of that there.  You also don't need to pass a quoted name as you did in your first statement.  If xval and yval are valid functions that can take an ename and a key and return the value from the key, then it would be close.  If you do a search, you might find others have faced this situation before and posted code.  I like the ones that filter by angle.  That said, you could try this substitute to filter your line selections unless I misunderstood your purpose.

 

(defun sslinedir
       (prmpt cmpr  / ssin ssout en)
  (prompt prmpt)
  (setq ssin (ssget '((0 . "line"))));;add filters as required
  (setq ssout (ssadd))
  (while (setq en (ssname ssin 0))
    (setq ei (entget en))
    (if (cmpr ei)
      (ssadd en ssout)
      )
    (ssdel en ssin)
    )
  ssout)

;;true if the line entity information is for a vertical line
;;you might add a fuzz factor for the third argument of the equal function
(defun  vert (ei)
  (equal (cadr(assoc 10 ei))
         (cadr(assoc 11 ei))
  ))
;;true if the line entity information is for a horizontal line
;;you might add a fuzz factor for the third argument of the equal function
(defun horz (ei)
  (equal (caddr(assoc 10 ei))
	 (caddr(assoc 11 ei))
	 ))

;;sample call
(setq ss (sslinedir "select lines" vert));;this returns vertical lines
(setq ss (sslinedir "select lines" horz));;this returns horizontal lines
Architect, Registered NC, VA, SC, & GA.
0 Likes
Message 7 of 9

martti.halminen
Collaborator
Collaborator
Accepted solution

 

You can use function names as parameters using APPLY, MAPCAR etc., which require the name as a symbol.

 

You could alternately use the actual function object as a parameter:

 

_$ (defun pick (func data)
        ;; testing functions as parameters
        (func data))
PICK
_$ (pick cdr '(1 . 2))
2
_$ (pick car '(1 . 2))
1

 

In this usage the name isn't quoted: just CAR instead of 'car or (function car), so what the program receives is the evaluated symbol value, looks like #<SUBR @0000000030089fc0 CAR> when printed.

 

-- 

 

0 Likes
Message 8 of 9

Anonymous
Not applicable
	(defun Xval (ENT ANUM) (cadr (assoc ANUM (entget ENT))))
	(defun Yval (ENT ANUM) (caddr (assoc ANUM (entget ENT))))

Here is what I was using for Xval & Yval.

 

And yea I realized when I was posting my code that it would probably make more sense to use the angle rather than compare endpoint values, but I was still curious about my original question.  The APPLY function is what I was looking for. I had forgetten about it since reading that chapter of the book, and when I was first going over it I even remeber thinking "What would this be used for?" Now I know. 

 

Thanks!

0 Likes
Message 9 of 9

dbroad
Mentor
Mentor

@martti.halminen  Thanks.  I did mention that in my second post that the unquoted form would be more convenient.  Thanks for the confirmation.

 

@Anonymous  Thanks.  Glad it worked out for you.

Architect, Registered NC, VA, SC, & GA.
0 Likes