Author Topic: about foreach  (Read 3681 times)

0 Members and 1 Guest are viewing this topic.

baitang36

  • Bull Frog
  • Posts: 213
about foreach
« on: April 19, 2022, 07:57:32 PM »
example:
(foreach n '(2 3 4) (print n))
Compile and decode this sentence

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F
00000000   0D 0A 20 46 41 53 34 2D  46 49 4C 45 20 3B 20 44      FAS4-FILE ; D
00000010   6F 20 6E 6F 74 20 63 68  61 6E 67 65 20 69 74 21   o not change it!
00000020   0D 0A 31 0D 0A 31 20 24  20 24 0D 0A 31 32 30 20     1  1 $ $  120
00000030   35 20 24 14 01 01 01 00  32 00 32 3F 2A 39 01 00   5 $     2 2?*9 
00000040   5B 50 52 49 4E 54 00 4E  00 00 32 02 32 03 32 04   [PRINT N  2 2 2
00000050   39 03 00 01 01 43 00 00  05 00 0A 01 5C 00 00 43   9    C      \  C
00000060   00 00 01 00 0A 01 43 05  00 00 00 1C 14 01 00 00         C         
00000070   00 09 04 00 0A 09 03 00  5D 00 00 09 02 00 01 18           ]     
00000080   03 00 01 5C 00 00 67 1C  00 00 00 0A 5C 00 00 28      \  g     \  (
00000090   06 02 00 5C 00 00 29 5D  00 00 03 02 00 35 01 01      \  )]     5 
000000A0   00 03 57 DC FF FF FF 19  01 00 16 16 00 67 57 36     W?

Symbols used:
03 / '(2 3 4 )
02 / N
01 / PRINT

Instruction bytecode and explanation:
09 03 00  ; '(2 3 4 )
5D 00 00 ;  (setq var1 '(2 3 4))  将'(2 3 4 )放入局部变量
09 02 00   ; N 
01 18 03 00 ;绑定一个局部变量 bind
01 ;nil
loc_1:
5C 00 00            ;局部变量 var1
67 1C  00 00 00  ;if指令,如果var1为空,转到解除绑定、结束
0A  ;NIL
5C 00 00  ;局部变量var1
28        ;car
06 02 00 ;(SETQ N (car var1))
5C 00 00 ;局部变量var1
29       ;cdr 
5D  00 00   ;  (setq var1(cdr var1))
03 02 00 ;N
35 01 01 00 03 ;(PRINT N)
57 DC FF FF FF   ;goto loc_1
19  01 00       ;解除绑定  Unbind
16                 ;结束    end

结论:Conclusion:
(foreach n '(2 3 4) (print n))相当于:Equivalent to:
(setq var1 '(2 3 4))
(while var1
  (SETQ N (car var1))
  (setq var1(cdr var1))
  (print N)
)       

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2139
  • class keyThumper<T>:ILazy<T>
Re: about foreach
« Reply #1 on: April 19, 2022, 09:19:28 PM »
example:
(foreach n '(2 3 4) (print n))
Compile and decode this sentence

<... >

结论:Conclusion:
(foreach n '(2 3 4) (print n))相当于:Equivalent to:
(setq var1 '(2 3 4))
(while var1
  (SETQ N (car var1))
  (setq var1(cdr var1))
  (print N)
)       


Most excellent post @baitang36
I can appreciate the work you've done to decipher the bytecode.
Well done !

Regards,
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

JohnK

  • Administrator
  • Seagull
  • Posts: 10646
Re: about foreach
« Reply #2 on: April 19, 2022, 09:24:05 PM »
I agree with, kdub. Another great post, baitang36!
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

baitang36

  • Bull Frog
  • Posts: 213
Re: about foreach
« Reply #3 on: April 20, 2022, 07:07:10 AM »
example:
(foreach n '(2 3 4) (print n))
Compile and decode this sentence

<... >

结论:Conclusion:
(foreach n '(2 3 4) (print n))相当于:Equivalent to:
(setq var1 '(2 3 4))
(while var1
  (SETQ N (car var1))
  (setq var1(cdr var1))
  (print N)
)       


Most excellent post @baitang36
I can appreciate the work you've done to decipher the bytecode.
Well done !

Regards,
thank you

baitang36

  • Bull Frog
  • Posts: 213
Re: about foreach
« Reply #4 on: April 20, 2022, 07:10:24 AM »
I agree with, kdub. Another great post, baitang36!
thank you

d2010

  • Bull Frog
  • Posts: 326
Re: about foreach
« Reply #5 on: April 20, 2022, 04:17:41 PM »
Dear baitang36, please you calculate the speed .
I got , in autocad2007, the function foreach is more faster that while......
But inside Autocad2022 or AutoCad2014?
 :smitten:

I agree with, kdub. Another great post, baitang36!
thank you

Code - Auto/Visual Lisp: [Select]
  1. (defun nn_vmload(fmtstr / itm cnt fns olde hpp zeo ss1 ss bou ask vlc arr pptx cec dyn eObj enoh)
  2.  (setq;|a000|;
  3.          ss (ssget fmtstr)
  4.          ss (if (=  ss nil) (ssget "X" fmtstr) ss)) (terpri) (setq;|a167007832|;
  5.          cnt (sslength ss)) (if (<  cnt 2) (progn  (alert readme.txt) (exit))) (dfn_cmd_canceld) (vl_load_com) (command "_.undo" "_BE") (setq;|a368356736|;
  6.          olde (getvar "cmdecho")) (setq;|a68071204|;
  7.          hpp (getvar "hpbound")) (setq;|a1633050988|;
  8.          itm 00) (setq;|a67427476|;
  9.          ss1 (ssadd)) (setq;|a186507072|;
  10.          zeo (entlast)) (ssadd zeo ss1) (setvar "HPBound" 0) (setvar "CMDECHO" 0) (setq;|a67123507|;
  11.          dyn (getint "\nColorCalc[1.yes/0.no]=")) (if (=  dyn 1) (while (setq;|a020|;
  12.          ent (ssname ss itm)) (progn  (setq;|a186504610|;
  13.          cec (dfn_color_ceinc (dfn_ent_colorce ent) (boole 1  (+ itm 24) 3))
  14.          eObj (vla-copy (vlax_ename2vla_object ent))
  15.          enoh (vlax_vla_object4ename eObj nil)) (command ".-hatchedit" (if enoh enoh ent) "b" "r" "y") (setq;|a001|;
  16.          itm (+ 1 itm)) (if enoh (setq;|a67639308|;
  17.          nop (vla-put-color eObj cec))))) (if (=  dyn 0) (while (setq;|a186506599|;
  18.          ent (ssname ss itm)) (progn  (command ".-hatchedit" ent "b" "r" "y") (setq;|a163619736|;
  19.          itm (+ 1 itm))))))
  20.  (while (setq;|a186508156|;
  21.          zeo (entnext zeo)) (ssadd zeo ss1))
  22.  (ssdel (ssname ss1 0) ss1) (command "_.union" ss1 "") (dfn_cmd_canceld) (setq;|a174|;
  23.          bou (entlast)) (command "_.hatch" "solid" "l" "") (dfn_cmd_canceld) (setq;|a67118217|;
  24.          ss2 (ssget "_L")) (setq;|a68293656|;
  25.          areaedit 0.0) (setq;|a15848|;
  26.          ask 0
  27.          vlc (getvar "VIEWCTR"))
  28.  (command "_.copy" (ssname ss 0) "" "0,0,0" "0,0,0" "_.erase" "p" "" "_.matchprop" "L" ss2 "" "_.draworder" ss2 "" "b" "_.erase" "L" bou ss "") (command "_.undo" "_E") (setvar "hpbound" hpp) (setvar "cmdecho" olde) (setq;|a000|;
  29.          pptx (getpoint "\nPoint-of-Areas.dic?")) (setq;|a67118177|;
  30.          arr (if pptx (dfn_ent_hatcharea ss2 -5003) -5002)) (setq;|a3421236|;
  31.          cec (if (>  arr 0) (dfn_ent_colorce ss2) nil)) (if cec (dfn_enamk_textsed pptx (strcat "Areas.dic=" (rtos arr 2 5))))
  32. $rr)
  33.  
« Last Edit: April 22, 2022, 12:47:52 PM by d2010 »

baitang36

  • Bull Frog
  • Posts: 213
Re: about foreach
« Reply #6 on: April 21, 2022, 08:32:48 PM »
Dear baitang36, please you calculate the speed .
I got , in autocad2007, the function foreach is more faster that while......
But inside Autocad2022 or AutoCad2014?
 :smitten:

I agree with, kdub. Another great post, baitang36!
thank you
Try compiling it into Fas and then compare the speed

kirby

  • Newt
  • Posts: 132
Re: about foreach
« Reply #7 on: April 22, 2022, 10:14:31 AM »
Trivial test, but didn't turn out as expected... (Acad 2018)

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

    (TEST_REPEAT MYLIST)......1188 / 1.22 <fastest>
    (TEST_WHILE MYLIST).......1391 / 1.04
    (TEST_FOREACH MYLIST).....1453 / 1 <slowest>

AcadVer = 22.0s (LMS Tech)



Code - Auto/Visual Lisp: [Select]
  1. (defun C:Test ()
  2. ; Benchmark various loop methods
  3. ; https://www.theswamp.org/index.php?topic=57519.0
  4. ; Uses custom functions:
  5. ;       Michael Puckett's benchmark utility
  6.  
  7.  
  8. (setq MyList '(1 2 3 4))
  9.  
  10. (benchmark
  11.         (list
  12.                 '(Test_foreach mylist)          ; foreach
  13.                 '(Test_while mylist)            ; while
  14.                 '(Test_repeat mylist)           ; repeat
  15.         )
  16. )
  17. (prompt "\nAcadVer = ")(princ (getvar "AcadVer"))
  18. )
  19.  
  20.  
  21. (defun Test_foreach (MyList / n)
  22. ; Foreach alterantive
  23. (foreach n MyList (print n))
  24. )
  25.  
  26.  
  27. (defun Test_while (MyList / var1 n)
  28. ; While alternative
  29. (setq var1 MyList)
  30. (while var1
  31.   (setq N (car var1))
  32.   (setq var1 (cdr var1))
  33.   (print N)
  34. )
  35. )
  36.  
  37.  
  38. (defun Test_repeat (MyList / CNT n)
  39. ; Repeat alternative
  40. (setq CNT 0)
  41. (repeat (length MyList)
  42.         (setq N (nth CNT MyList))
  43.         (print N)
  44.         (setq CNT (1+ CNT))
  45. )
  46. )
  47.  


mhupp

  • Bull Frog
  • Posts: 250
Re: about foreach
« Reply #8 on: April 22, 2022, 05:43:13 PM »
Elapsed milliseconds / relative speed for 512 iteration(s):

    (TEST_FOREACH MYLIST).....1969 / 1.04 <fastest>
    (TEST_WHILE MYLIST).......1984 / 1.03
    (TEST_REPEAT MYLIST)......2047 / 1.00 <slowest>

---- Benchmark Utility: In memory of Michael Puckett ----
AcadVer = 21.0 BricsCAD

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: about foreach
« Reply #9 on: April 22, 2022, 07:08:57 PM »
If the benchmark makes only 512 iterations to process a list of only 4 elements, it is because the processing is (very) slow.

This is due to the 'print' function which monopolizes almost all the processing time.

This kind of benchmark is not reliable to compare 'repeat', 'while' and 'foreach'.

With a longer list, the use of 'repeat' would certainly be slower, not because of 'repeat' itself, but because of the use of 'nth'.

Comparing the performance of these three functions doesn't really make sense, because they don't have the same use, 'foreach' can only be used with a list, and doing list processing with 'repeat' is nonsense.

Let's try some more reliable comparison by building three functions to simply reverse a list.

Code - Auto/Visual Lisp: [Select]
  1. (defun reverse_foreach (l / r)
  2.   (foreach n l
  3.     (setq r (cons n r))
  4.   )
  5. )
  6.  
  7. (defun reverse_while (l / r)
  8.   (while l
  9.     (setq r (cons (car l) r)
  10.           l (cdr l)
  11.     )
  12.   )
  13.   r
  14. )
  15.  
  16. (defun reverse_repeat (l / i r)
  17.   (setq i 0)
  18.   (repeat (length l)
  19.     (setq r (cons (nth i l) r)
  20.           i (1+ i)
  21.     )
  22.   )
  23.   r
  24. )

Now let's try a new benchmark with a more significant list (256 items)
Code - Auto/Visual Lisp: [Select]
  1. (repeat (setq i 256) (setq l (cons (setq i (1- i)) l)))

Code: [Select]
Benchmarking ................Elapsed milliseconds / relative speed for 8192 iteration(s):

    (REVERSE_WHILE L).......1500 / 2.35 <fastest>
    (REVERSE_FOREACH L).....1562 / 2.26
    (REVERSE_REPEAT L)......3531 / 1.00 <slowest>

We can immediately see the relative inefficiency of repeat for this kind of task.
And if while seems to be faster than foreach, we should not focus on the "relative speed" (2.26 vs 2.35) but try to see what this represents concretely. The difference between foreach and while is 62 milliseconds for 8192 iterations, in other words about 0.0076 milliseconds for processing one list.
« Last Edit: April 23, 2022, 02:30:50 AM by gile »
Speaking English as a French Frog

d2010

  • Bull Frog
  • Posts: 326
Re: about foreach
« Reply #10 on: April 23, 2022, 03:40:32 AM »
Here you test the speed with two more function/s?
Can you replace the (> var1 0) with T? for max=speed you replace (> var1 0)
with 1?
Can you BenchmarkTest these lines-sources 001= ,002= , 003=, 004=? 
???
Code - Auto/Visual Lisp: [Select]
  1. 000=(setq lst '(1 2 3 4))
  2. 001=(vl-every '(lambda(var1) (> var1 0) (list (setq n var1) (princ n))) lst)
  3. 002=(vl-every '(lambda(var1) (> var1 0) (vector (setq n var1) (princ n))) lst)
  4. 003=(vl-every '(lambda(var1) (> var1 0) (progn (setq n var1) (princ n))) lst)
  5. 004=(vl-every 'print lst)
  6.  
:cry:
(defun Test_every (MyList / n)
  (setq n (car MyList))
  (vl-every 'print MyList)
  (print)
)
(setq lst '(1 2 3 4))
(setq vec (vector 1 2 3 4))
(grread)
(alert "okai")
Elapsed milliseconds / relative speed for 512 iteration(s):

    (TEST_FOREACH MYLIST).....1969 / 1.04 <fastest>
    (TEST_WHILE MYLIST).......1984 / 1.03
    (TEST_REPEAT MYLIST)......2047 / 1.00 <slowest>

---- Benchmark Utility: In memory of Michael Puckett ----
AcadVer = 21.0 BricsCAD

« Last Edit: April 23, 2022, 03:56:21 AM by d2010 »

mhupp

  • Bull Frog
  • Posts: 250
Re: about foreach
« Reply #11 on: April 24, 2022, 03:47:25 AM »
We can immediately see the relative inefficiency of repeat for this kind of task.

I think it shows the inefficiency of nth. rewrote the repeat function to match the while function. Useing the 256 list these are my results.

Code - Auto/Visual Lisp: [Select]
  1. (defun reverse_repeat (l / r)
  2.   (repeat (length l)
  3.     (setq r (cons (car l) r)
  4.           l (cdr l)  
  5.     )
  6.   )
  7.   r
  8. )

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

    (REVERSE_REPEAT L)......1297 / 1.36 <fastest>
    (REVERSE_WHILE L).......1328 / 1.33
    (REVERSE_FOREACH L).....1766 / 1.00 <slowest>

---- Benchmark Utility: In memory of Michael Puckett ----
AcadVer = 21.0 BricsCAD
« Last Edit: April 24, 2022, 03:55:24 AM by mhupp »

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: about foreach
« Reply #12 on: April 24, 2022, 05:54:03 AM »
I think it shows the inefficiency of nth..
You are absolutely right.

Anyway, I think we have to keep in mind what does your results really means.
The difference between the fastest (reverse_repeat) and the slowest (reverse_foreach) is equal to (/ (- 1766 1297) 65536.) => about 0.007 milliseconds to process a list of 512 items.
By my side, I'd rather use foreach for this kind of task, despite the fact if is 'slower', because it allows to write the code a more declarative and self explanatory way.
With foreach, the code describes what you want it to do; with repeat or while, the code details how it should do it. I prefer to let the interpreter (or compiler) handle the how part (as shown by baitang36).
Over time, I've learned that it's better to spend time writing directly understandable code than to chase hundredths of a millisecond.
Speaking English as a French Frog

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: about foreach
« Reply #13 on: April 24, 2022, 07:55:27 AM »
By my side, I'd rather use foreach for this kind of task, despite the fact if is 'slower', because it allows to write the code a more declarative and self explanatory way.
With foreach, the code describes what you want it to do; with repeat or while, the code details how it should do it. I prefer to let the interpreter (or compiler) handle the how part (as shown by baitang36).
Over time, I've learned that it's better to spend time writing directly understandable code than to chase hundredths of a millisecond.

Well said, I couldn't agree more.

mhupp

  • Bull Frog
  • Posts: 250
Re: about foreach
« Reply #14 on: April 24, 2022, 01:36:35 PM »
I was just trying to show empirical data. I also prefer to use foreach for the reason you stated and the simplicity. never really liked processing selection sets with a counter


Code - Auto/Visual Lisp: [Select]
  1. (setq i 0)
  2. (if (setq ss (ssget))
  3.   (repeat (sslength ss)
  4.     (setq ent (ssname ss i))
  5.     ... do stuff
  6.     (setq i (1+ i))
  7.   )
  8. )

its just cleaner with foreach
Code - Auto/Visual Lisp: [Select]
  1. (if (setq ss (ssget))
  2.   (foreach ent (vl-remove-if 'listp (mapcar 'cadr (ssnamex SS)))
  3.     ... do stuff
  4.   )
  5. )