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.
(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:
((deriv 'cube) 5)
This is what the return should essentially be:
(
(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.
;; =====================================
;; Procedures as returned values
;; -------------------------------------
; Setup
;
(setq dx
0.00001) ; -Constant `dx` (defun cube
(x
) (* x x x
)) ; -Definition for `cube`
; OBJECTIVE
; This is how we'd like to write our function.
;
(/ (- (g (+ 'x 'dx)) (g 'x))
'dx))
)
; (OBJECTIVE) USE
; This is how we'd like to use our function.
;
((deriv 'cube) 5)
; > 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.
;; Method 1 for returned procedure.
;; This is a basic method for returning a procedure. The only
;; complication is the need to "eval g".
;;
;; The USE of this method isn't as clean as the OBJECTIVE.
;; using SETQ
dx)
)
)
; USE
(
5)
; > 75
;; Method 2 for a returned procedure.
;; This method will bind the number 5 to a local variable of x which is required by `deriv`.
;;
;; The USE of this method isn't as clean as the OBJECTIVE.
;; using SET
dx)
)
)
;; OR using DEFUN
(/ (- ((eval g
) (+ x dx
)) ((eval g
) x
)) dx
) )
; USE
(
(deriv 'cube))
5)
;; OR using a syntactic-shortcut
(
'((x)
(deriv 'cube))
5)
; > 75
;; Method 2a
;; this method eliminates the use of a quoted symbol (non typical for
;; AutoLisp)
(/ (- (g (+ x dx)) (g x)) dx)
)
; USE
(
'((x)
(deriv cube))
5)
; > 75
;; Method 3; construct a lambda statement.
;; This method will "build" a function.
;;
;; This method allows for a clean usage like in other Lisp dialects
;; but is clumsy to construct.
'dx)
)
)
)
;; OR using SET to differentiate a different "type of function".
'dx)
)
)
)
)
; USE
((deriv 'cube) 5)
; > 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).
;; Method 4;
;; This method will result in a usage that is more familiar to AutoLisp
;; users.
dx)
)
(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.