Author Topic: Functions as returned values  (Read 740 times)

0 Members and 1 Guest are viewing this topic.

JohnK

  • Administrator
  • Seagull
  • Posts: 10643
Functions as returned values
« on: June 09, 2023, 02:35:47 PM »
There is a common practice in programming of supplying a function as an argument to complete operations, but the other side of this operation is to return a function. I abandoned looking into this a long time ago but I came across the section in a book again and decided to give it a try. The example the book used was for a calculation and here is how it looks.

Code: [Select]
(defun cube (x) (* x x x))
(setq dx 0.00001)

(defun deriv (g)
  (lambda (x)
    (/ (- (g (+ x dx)) (g x))
       dx))
  )

The thing to notice is how the parameter `g` is supposed to be replaced with `cube` and the lambda statement is supposed to be returned.

So, the use of this is supposed to be like the following:
Code: [Select]
((deriv 'cube) 5)

This is what the return should essentially be:

Code: [Select]
(
 (lambda (x)
   (/ (- (cube (+ x dx)) (cube x))
      dx))
 5)

So, in other words, the ((deriv 'cube) 5) statement is supposed to replace all the `G` variables in the `deriv` function with the `CUBE` function which should result in a LET-CONSTRUCT.

As far as I knew this should work but as I soon discovered it's not as cut-and-dried as I thought. -i.e. I had thought AutoLisp had lexical scope which means the value of G and X are separate (AL, starts at the innermost function and works outwards which should result in: G is the value of "(deriv 'cube)" and X is 5 after you do the "(deriv 'cube)" part but what happened was G and X both ended up being 5 (in some tests, depending on the syntax used) and cube wasn't anywhere to be found!?) so I'm now discovering that AutoLisp has a "dynamic scope" (a sort of "list of variables and values").

So let's go down the rabbit hole testing different syntaxes.
Code - Auto/Visual Lisp: [Select]
  1. ;; =====================================
  2. ;; Procedures as returned values
  3. ;; -------------------------------------
  4.  
  5. ; Setup
  6. ;
  7. (setq dx 0.00001)             ; -Constant `dx`
  8. (defun cube (x) (* x x x))    ; -Definition for `cube`
  9.  
  10. ; OBJECTIVE
  11. ; This is how we'd like to write our function.
  12. ;
  13. (defun deriv (g)
  14.   (lambda (g)
  15.     (/ (- (g (+ 'x 'dx)) (g 'x))
  16.        'dx))
  17.   )
  18.  
  19. ; (OBJECTIVE) USE
  20. ; This is how we'd like to use our function.
  21. ;
  22. ((deriv 'cube) 5)
  23. ; > This returns an error: no function definition nil.


To create this, we cannot use the above code and we only have a few methods for achieving something similar.

Code - Auto/Visual Lisp: [Select]
  1. ;; Method 1 for returned procedure.
  2. ;; This is a basic method for returning a procedure. The only
  3. ;; complication is the need to "eval g".
  4. ;;
  5. ;; The USE of this method isn't as clean as the OBJECTIVE.
  6.  
  7. ;; using SETQ
  8. (setq deriv
  9.       (lambda (g)
  10.         (/ (- ((eval g) (+ x dx)) ((eval g) x))
  11.            dx)
  12.         )
  13.       )
  14. ; USE
  15. (
  16.  (lambda (x)
  17.    (eval (deriv 'cube)))
  18.  5)
  19. ; > 75


Code - Auto/Visual Lisp: [Select]
  1. ;; Method 2 for a returned procedure.
  2. ;; This method will bind the number 5 to a local variable of x which is required by `deriv`.
  3. ;;
  4. ;; The USE of this method isn't as clean as the OBJECTIVE.
  5.  
  6. ;; using SET
  7. (set 'deriv
  8.       (lambda (g)
  9.         (/ (- ((eval g) (+ x dx)) ((eval g) x))
  10.            dx)
  11.         )
  12.       )
  13.    
  14. ;; OR using DEFUN
  15.  
  16. (defun deriv (g)
  17.   (/ (- ((eval g) (+ x dx)) ((eval g) x)) dx)
  18.   )
  19.  
  20. ; USE
  21. (
  22.  (lambda (x)
  23.    (deriv 'cube))
  24.  5)
  25.  
  26. ;; OR using a syntactic-shortcut
  27.  
  28. (
  29. '((x)
  30.   (deriv 'cube))
  31. 5)
  32.  
  33. ; > 75

Code - Auto/Visual Lisp: [Select]
  1. ;; Method 2a
  2. ;; this method eliminates the use of a quoted symbol (non typical for
  3. ;; AutoLisp)
  4.  
  5. (defun deriv (g)
  6.   (/ (- (g (+ x dx)) (g x)) dx)
  7.   )
  8.  
  9. ; USE
  10. (
  11.  '((x)
  12.    (deriv cube))
  13.  5)
  14. ; > 75
  15.  

Code - Auto/Visual Lisp: [Select]
  1. ;; Method 3; construct a lambda statement.
  2. ;; This method will "build" a function.
  3. ;;
  4. ;; This method allows for a clean usage like in other Lisp dialects
  5. ;; but is clumsy to construct.
  6. (defun deriv (g)
  7.   (eval
  8.     (list 'lambda (list 'x)
  9.           (list '/ (list '- (list g (list '+ 'x 'dx)) (list g 'x))
  10.                 'dx)
  11.           )
  12.     )
  13.   )
  14.  
  15. ;; OR using SET to differentiate a different "type of function".
  16.  
  17. (set 'deriv (lambda (g)
  18.               (eval
  19.                 (list 'lambda (list 'x)
  20.                       (list '/ (list '- (list g (list '+ 'x 'dx)) (list g 'x))
  21.                             'dx)
  22.                       )
  23.                 )
  24.               )
  25.      )
  26.  
  27. ; USE
  28. ((deriv 'cube) 5)
  29. ; > 75

Methods #1 and #2 are very similar in construction and use.
Method #3 is constructed very differently but is used with a cleaner syntax.

Of course, we can always just go the normal route and create a formal argument for X and "normalize" the call (this is what everyone is used to seeing/using).

Code - Auto/Visual Lisp: [Select]
  1. ;; Method 4;
  2. ;; This method will result in a usage that is more familiar to AutoLisp
  3. ;; users.
  4. (defun deriv (g x)
  5.   (/ (- ((eval g) (+ x dx)) ((eval g) x))
  6.      dx)
  7.   )
  8.  
  9. (deriv 'cube 5)

The concept of returning a function is hit-or-miss in AutoLisp but then again this concept is on a razor's edge of causing unnecessary code abuse and/or obfuscation and it's use should be limited to special cases. However, it was a fun little rabbit hole to go down.

I may have forgotten/omitted a few syntax-shortcuts so if you notice one, please let me know.

TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

d2010

  • Bull Frog
  • Posts: 326
Re: Functions as returned values
« Reply #1 on: June 11, 2023, 06:40:49 AM »
In ZwCad 2022, not work, perhaps other'sCad (BrisCad, GstarCad, TurboCad, Ncad, ) are too imcompatibile
--with the CommonLisp?)

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2139
  • class keyThumper<T>:ILazy<T>
Re: Functions as returned values
« Reply #2 on: June 11, 2023, 04:34:30 PM »
I wonder what Common Lisp has to do with the issue ??


fwiw:

In ac2024:
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.