Nesting and Booleans
Posted: Mon Jul 05, 2010 12:02 am
My mind wanders around a lot and I find that I have something more to say about function nesting and how it turned out to be involved with boolean statements. To see the relation takes a while but please bear with me.
If we have a nested statement such as (sin (cos 0.5)) we instinctively want to simplify it to (sin cos 0.5) but are frustrated in that the current syntax doesn't allow us to do that. So the good lisper can write himself a function that we will call NEST and then be able to write something like (nest sin cos 0.5). This may be elegant but in most cases does not satisfy because we must type another five characters (don't forget the space). Often the nesting you actually run across only goes for two levels and it is just easier to type the two parentheses, this approach only starts to have value at three levels of nesting. We can't get rid of that desire to type (sin cos 0.5)! A lisper always wants to do the least typing possible. For fun I wrote this function
I hope someone writes a better version of this because I am pretty sure I didn't take the best approach. This function takes advantage of the fact that all functions that are capable of nesting only have a single argument. And we can use this frame to redefine all of the existing single argument functions if we wish. Here is a demonstration example with the SIN and COS functions:
Using these new functions you can now write (sn cs 0.5) and get the desired result. If you redefine all of NewLisp's single argument functions and your own this way you can have built-in nesting the way God intended!
However I ran across a case where making all single argument functions act this way is undesirable. I found that boolean functions that take single arguments should be treated in a different manner. I came up with this fun little piece of code:
What this function does is allow any boolean function to double as its own if/then/else conditional statement. How does this work? Suppose we define a new version of the INTEGER? function as
Now if we write (new-integer? 3) this behaves the same way as integer? does. But if we were to write (new-integer? 3 "A" "B") it now behaves like (if (integer? 3) "A" "B"). We now don't have to write the IF statement!
So we have two conflicting desires here, we can't make all single argument functions have nesting behavior and be able to have built-in conditionals at the same time. I have concluded that this is not a problem in practice because almost all nested statements that I have run across do not tend to have conditionals in them or at least rarely. Therefore I propose that all boolean functions (functions that return true or nil) have built-in conditional capability and that all other single argument functions have built-in nesting. This could be further advanced by having two new functions DEFINE-BOOL and DEFINE-NEST so that users could define such functions right from the beginning. How would this work? Let us say that we want to define a new boolean function that determines whether a number is even or odd. We will call this function EVEN?. I envisage writing something like
The user only has to supply the name of the function and the code for the logical test. $X represents an internal variable that stands for the single argument that the function takes for the default case. All of the rest of the overhead is taken care of by DEFINE-BOOL. A similar technique would be used for a DEFINE-NEST function.
I believe that there cumulative advantages to implementing both of these approaches to NewLisp. It doesn't break previous code but adds a great enhancement. Wouldn't it be nice to get rid of a lot of IF statements? Anyone have any thoughts on the matter?
If we have a nested statement such as (sin (cos 0.5)) we instinctively want to simplify it to (sin cos 0.5) but are frustrated in that the current syntax doesn't allow us to do that. So the good lisper can write himself a function that we will call NEST and then be able to write something like (nest sin cos 0.5). This may be elegant but in most cases does not satisfy because we must type another five characters (don't forget the space). Often the nesting you actually run across only goes for two levels and it is just easier to type the two parentheses, this approach only starts to have value at three levels of nesting. We can't get rid of that desire to type (sin cos 0.5)! A lisper always wants to do the least typing possible. For fun I wrote this function
Code: Select all
(define-macro (nest)
(setq op (args 0) rargs (rest (args)))
(op (eval (if (symbol? (rargs 0))
(begin
(setq r (rest (rargs))
lst (rargs -1)
r (if (symbol? lst)
(setf (r -1)(list lst))
r
)
)
(apply (rargs 0)(map eval r))
)
(rargs 0)
))))
Code: Select all
(define-macro (sn) (nest sin ))
(define-macro (cs) (nest cos ))
However I ran across a case where making all single argument functions act this way is undesirable. I found that boolean functions that take single arguments should be treated in a different manner. I came up with this fun little piece of code:
Code: Select all
(define (bool-if func x A B)
(if (or A B)
(eval (if (func x) A B))
(func x)))
Code: Select all
(define (new-integer? x A B)
(bool-if integer? x A B))
So we have two conflicting desires here, we can't make all single argument functions have nesting behavior and be able to have built-in conditionals at the same time. I have concluded that this is not a problem in practice because almost all nested statements that I have run across do not tend to have conditionals in them or at least rarely. Therefore I propose that all boolean functions (functions that return true or nil) have built-in conditional capability and that all other single argument functions have built-in nesting. This could be further advanced by having two new functions DEFINE-BOOL and DEFINE-NEST so that users could define such functions right from the beginning. How would this work? Let us say that we want to define a new boolean function that determines whether a number is even or odd. We will call this function EVEN?. I envisage writing something like
Code: Select all
(define-bool (even?)
(zero? (% $X 2))
)
I believe that there cumulative advantages to implementing both of these approaches to NewLisp. It doesn't break previous code but adds a great enhancement. Wouldn't it be nice to get rid of a lot of IF statements? Anyone have any thoughts on the matter?