Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - Jeremy Dunn

#1
This post is simply my amateur musings about the future of programming and asking your thoughts. One of things I was hoping would improve would be that the environment would allow you to write code in any language that you wanted so that usefullness would determine what languages would be used. Every application I own locks me into limited languages instead of giving me freedom. Why is this and what can be done about it?



Is Mathematica the future? It is up to 2700+ functions and counting. Is this a new idea to simply grow the language to the point where it starts eating everything around it? There is something to be said for this approach and I think we can agree that Mathematica is a pretty cool product. Is Mathematica going to be like China and quietly grow in the background until everyone realizes too late that they can't stop it?



What is the syntax of the future? Can much more be done? We here obviously prefer LISP syntax because of (to us) its simplicity. Why has no one done objective testing of different languages to determine which ones are most likely to be difficult to learn or apply properly? Why is there nothing but idiotic flaming wars on the subject? You would think the software industry would investigate this more with billions of manhours of work on the line. Is it like music where one person likes jazz and another prefers classical with no objective standard? Do two people prefer different syntaxes because their brains actually perceive differently and the different syntaxes are ideal to that type of thought? Can we show that a given language is better even though another one is the individuals favorite pick?



What trends to do you see? What do you think the future of programming will be?
#2
Whither newLISP? / Handy looping function
March 02, 2009, 06:21:41 PM
First the code:



(define (dolist-choice n A B C)
  (if (list? n)
      (setq n (dec (length n))))
  (eval (if C
           (if (zero? $idx) A (= $idx n) B C)
           (if (member $idx '(0 n)) A B)
        )
  )
)


This is a special branching function designed for being used within a DOLIST loop. The function can take up to 4 arguments. The first argument is either the list we are looping through or the integer value of the largest index of the list. If we supply a list then the largest index is found for us. A, B, C are each one or more program statements to be executed. If we have all three then if $idx is 0 A is executed else if $idx is the last index B is executed else if $idx is any other index then C is executed. If only A and B are present then if $idx is the first or last index A is executed else B is. I find this one very handy for the toolbox and it can really clean things up - enjoy!
#3
newLISP newS / Add and Mul
February 23, 2009, 07:43:54 PM
Some possible enhancements to add and mul:



ADD



When supplied with a single vector return the sum of all of the elements

(add (1 2 3 4)) -> 10



When supplied with an integer and T return the continued sum of the digits of the integer.

(add 7898 T) -> 7+8+9+8 = 32  3+2 = 5



MUL



When supplied with a single positive integer return the factorial of that integer.

(mul 3) -> 6



When supplied with a single negative integer return the double-factorial of the absolute value of the integer.

(mul -7) -> 105



When supplied with a single vector return the product of the elements.

(mul (1 2 3 4)) -> 24



When supplied with an integer and T the continued product of the integer digits is returned.

(mul 463 T) -> 4*6*3 = 72 7*2 = 14
#4
newLISP newS / dup
February 06, 2009, 11:51:07 AM
Lutz,



Why not make DUP take additional multiplier arguments so that

(dup x n1 n2 n3 ....) is the same as (dup (dup (dup x n1) n2) n2)? That way if I want a 3x3 matrix of zeros I can write (dup 0 3 3) instead of (dup (dup 0 3) 3).
#5
Anything else we might add? / Folding and Such
December 21, 2008, 10:19:29 AM
In our code snippets is a little function for doing alternating addition and subtraction that enables you to write an expression like a+b-c+d.. as



(+- a b c d ...)



which is just a shorthand for (+ (- (+ a b) c) d). One immediately thinks about generalizing this for any two functions A and B to get (A (B (A a b) c) d). But wouldn't it be even more general to allow any number of functions so that we could have expressions like (B (A (C (B (A a b) c) d) e) f)? I then considered that there are really four cases that we might have that are variations of whether we reverse the order of arguments or of the direction we apply the operators in. They are



(B (A (C (B (A a b) d) e) f) g)

(B f (A e (C d (B c (A a b)))))

(A (B (C (A (B a b) d) e) f) g)

(A f (B e (C d (A c (B a b)))))



So I came up with a FOLD function that does all this. One first lists the operators, a comma and then the arguments. The first function is quoted if you want to reverse the arguments and the second function is quoted if you want to reverse the operator order. For instance, the above four cases would be written as



(fold A B C , a b c d e f g)

(fold 'A B C , a b c d e f g)

(fold A 'B C , a b c d e f g)

(fold 'A 'B C , a b c d e f g)



Here is the code for doing this


 
(define-macro (fold)
 (local
  (ind funcs funcL vars varL start flg1 flg2 f)
  (setq ind   (find , (map eval (args)))  ;find where the colon is
        funcs (0 ind (args))      ;get a list of the functions
        vars  ((inc ind)(args))   ;get a list of the arguments to process
        funcL (length funcs)      ;get the number of functions
        varL  (length vars)       ;get the number of variables
  )
  ;..if the argument is a list then set vars to the list and process that
  (if (list? (args -1))
      (setq vars (args -1))
  )
  (setq flg1 (symbol? (eval (funcs 0))))  ;set flag to reverse argument order
  (setq flg2 (symbol? (eval (funcs 1))))  ;set flag to reverse operator order
  (when (>= varL 3) ;we must have at least 3 arguments to process
    (setq start (eval (list (eval (funcs 0))
                            (vars 0)
                            (vars 1))))  ;do the first calculation
    ;loop thru the rest of the arguments
    (dolist (a (2 vars))
      (setq f     (funcs (dec (% (if flg2 (- varL $idx) $idx) funcL)))
            start (eval (push (eval f) (if flg1 (list a start)(list start a))))
      ))
    start
  )))


So now we could write (+- a b c d e) or the more general (fold add sub , a b c d e). Another case of repetitive operations are continued fractions. For instance, the simplest continued fraction is that for the golden ratio (1.618) which can be represented now as (fold 'add 'div , 1 1 1 1 1 1 1). Of course you need a lot of ones to converge on phi. You must remember that all functions must be able to take a minimum of two arguments.



I believe this function is sufficiently general to be a handy one in the toolbox. A caveat: I wanted this function to be able to take a list of arguments like

(fold 'add 'div , (list 1 1 1 1 1)) as well but my section of code for doing that doesn't seem to work. Can anyone tell me what I did wrong? I have a devil of a time knowing when to EVAL and when not to to get things to process correctly :-)
#6
newLISP newS / $idx
July 29, 2008, 05:59:26 PM
Now that $idx has been added to all looping structures could it be useful to also have two more? I wanted to suggest having two more locals named $prev and $next that would be defined as



$prev = $idx - 1

$next = $idx + 1



Often in loops it is the previous or next element that I am interested in also, this would provide a convenient way to get to them rather incrementing or decrementing explicitly.
#7
Anything else we might add? / Cyclic Permutation
July 25, 2008, 10:52:03 AM
Greetings all lispers! I have run across a situation that I am sure some of you have too where one has an expression that involves the repetition of a form that has a cyclic permutation of arguments. For instance, suppose we have



(add (mul (sin A)(sin B))(mul (sin B)(sin C))(mul (sin C)(sin A)))



It is clear we are just cycling through our arguments and wasting a lot of verbiage. I would like to create a function that I will call CYCLIC that enables me to write this something like



(apply add (cyclic '(A B C) '(mul (sin *1)(sin *2))))



In the previous we have a list of the actual values '(A B C) that we want to cycle through and then we have the expression to substitute into. The expression has filler variables *1, *2 ...  I am not sure of how to go about this. Should my expression be a quoted symbol or would it be better to have it as a string to chop apart and evaluate? It is the creation of dummy arguments *1, *2 etc that is puzzling me.
#8
Here is a conditional form that I find very useful



(define (<=> x y body1 body2 body3)
  (if (list? x)(setq x (length x)))
  (if (list? y)(setq y (length y)))
  (eval (if (< x y) body1
            (= x y) body2
            body3
        )))


This is a conditional with three bodies. X and Y can either be a list or a number. If X or Y is a list then the length of the list is used for comparison. The conditional looks at the two numbers X and Y. If X<Y body1 is executed elseif X=Y body2 is executed else body3 is executed. This happens a lot and I wish I would have thought of this a long time ago.
#9
I love it when I find something simple and useful. One of the things we notice with boolean functions is that they invariably are inside an If...then... expression. Now sometimes we want the truth value of the statement but many times we are only using it to decide whether we are going to use the argument that was input or not. For instance,



(if (< x)(setq z x))


In this case we do not need the truth value itself but only x. Now suppose we wrote the following function



(define-macro (rtn)
  (if (eval (args))
      (eval (args 1))))


Now we could write the previous as (setq z (rtn < x)). This eliminates always having to write the conditional statement. RTN can be used with booleans that take more than one argument. For instance,

(if (= x y)(setq z x)) would be (setq z (rtn = x y)). If the boolean test is true then the first argument of the multiple arguments is returned. The name RTN is an abbreviation of RETURN because the function returns the input when true.



Now we may not be setting the value to a variable but just using it directly in a calculation as in



(if (< x y)(* x 4))


But using RTN this becomes simply (* (rtn < x y) 4). I think you'll agree that this happens quite a lot. Hope you find it useful.
#10
Anything else we might add? / Redefine DEFINE?
January 30, 2008, 06:40:30 PM
I wanted to revisit the subject of nested expressions, particularly functions that take a single argument only. For example, we could have



(sin (abs (ceil x)))



Fanda wrote a wonderful function he called PASS that enabled us to write this as



(pass (sin abs ceil) x)



That's pretty good but could we do better? I came to thinking about this when I was writing a redefinition of the NOT function as



(define-macro (n)
 (if (true? (args 0)) nil
     (nil? (args 0)) true
     (not (eval (if (= 1 (length (args)))) (args 0) (args))))
 ))


(n x) is equivalent to (not x). The difference occurs when you write an expression like (not (= x y)). Using the N function you can now rewrite this as (n = x y). Gets rid of parentheses. After doing this it occured to me that the same principle can be applied to ANY single argument function. This leads me to suggest the following: Let us have a slight redefinition of the DEFINE function so that if we are defining a function with a single argument that it behaves in this manner if it receives more than one argument. The first argument will be assumed to be the name of a function and all further arguments are considered to be its arguments. By doing this all single argument functions that exist and that will ever be written will have the property of nesting with each other. If this is so then we can simply write



(sin (abs (ceil x)))



as the more natural



(sin abs ceil x)



without the need for any PASS type of function at all. I think this solution is better than PASS because in this case when using PASS you eliminate 2 parentheses but must type PASS for a net gain of two characters. You would need a nesting at least 4 levels deep to finally get a net gain in typing. Doing it my way results in a gain for typing at any level of nesting since the behavior is part of the functions to begin with. If DEFINE cannot be changed then perhaps we could have a DEFINE-SINGLE command to deal with single argument functions.
#11
Anything else we might add? / Suggestions for DOLIST
January 12, 2008, 02:59:53 PM
In thinking about the DOLIST command I had some ideas that might be useful. The protected symbol $idx stores the current loop index. I would suggest having two more protected symbols that would be called $length and $last. $length stores the length of the list and $last stores the last index or $length - 1. This way if I want to find out if I'm on the last index I can just write (= $idx $last).



Another possible change would be adding to the general structure. The current structure is



(dolist (sym list break) body)



I would like this changed to



(dolist (sym list break body-1st body-last body-nth) body)



This would would work as follows: The extra bodies can either be single expressions or groups of statements thrown together using BEGIN. On the 1st element of the loop the statements in body-1st are executed, on the last element of the loop the statements in body-last are excecuted and for all other elements body-nth is executed. Any operations that occur for all elements are exectued in body as normal.



Now if we have the form



(dolist (sym list break body-1st/last body-nth) body)



where we only have two bodies then the 1st body is executed for the 1st and last elements while the 2nd occurs for all others. And naturally if there are no extra bodies then just body is executed and the loop behaves as it traditionally has. I think doing things this way would get rid of a lot of repetition as it seems the user is often having to test if they are on the 1st or last elements.
#12
I have a situation where I want to determine if my function received +2 vs just 2 from the user. If I use "integer?" as my test both versions return true. If I try using "string" both values return "2". Is there any way to identify a positive signed integer versus a positive unsigned integer? If not, could "string" be modified to return the input literally?
#13
Anything else we might add? / Useful Math Function
November 23, 2007, 01:31:07 PM
This function is basically a counterpart to the SQRT function and serves a useful purpose. I originally had two separate functions but then realized that I could combine them both.



;; This function takes one or more numbers as arguments. If there is a single
;; number the number is squared. If there is more than one number then the square
;; root of the sum of the squares (a^2 + b^2 + c^2 + ...)^1/2 is returned.
;; Example: (sq 3) -> 9
;;          (sq 2 3) -> 3.605551275
(define-macro (sq)
  (if (= (length (args)) 1)
      (mul (args 0)(args 0))
      (sqrt (apply add (map mul (args)(args))))))
#14
Anything else we might add? / A 3D Text Editor?
October 10, 2007, 07:29:06 PM
I was thinking about the nature of LISP syntax and its nesting parentheses that programmers from other languages seem to go into fits over. What if we could get rid of the parentheses? I gave some considerable thought to this problem and I realized that LISP lends itself to a novel solution. What if our code writing text editor had a third axis that we could move the cursor up and down in? Imagine your normal text editor but with the main XY plane displayed in an isometric view so that it was like you were looking down on it at an angle. Imagine further that you could hit SHIFT-DOWN ARROW or SHIFT-UP ARROW to move the cursor up or down a level from the main text plane. Now imagine that every time that you type the name of a function you then move the cursor DOWN into the plane and type the rest of the arguments going up or down as needed to indicate the nesting. Comments could be written on the +1 level (above the home plane). This way we could eliminate the display of the parentheses entirely by using visual depth as a substitute. I am currently starting to write such an interface but I am doing so in AutoCAD to write AutoLISP code in a DWG file. The DWG file is read by a translator and the drawing entities in it are converted to AutoLISP code. The 3D display environment already exists so I don't have to write it. I intend to display spaces as light grey filled rectangles to add visual clues to help define the current plane that the text is on. I also intend to use this interface to write NEWLISP code as well but it would only benefit NEWLISP users that have copy of AutoCAD on their computer. A good project for you adept GUI writers out there?



What do the rest of you think of this concept? Profound? Nutty?



Short of that what can we do in boring old 2D land? One idea I had was to make LISP case sensitive so that the function names can be written in a format that makes them unique. For instance, a function name would be upper-case with at least one letter at the beginning. This way the interpreter could identify a function name and automatically assume a left parenthesis in front of it. You would still have to type the right parentheses but it would get rid of 50% of them.



My final idea was to allow the use of square brackets [] as well as parentheses. A square bracket would be equivalent to two parentheses. So an expression like (f1 (f2 (f3 (f4 x)))) could be written as

(f1 (f2 (f3 (f4 x]] . At least we could shorten some of those more massive collections of parentheses that sometimes occur at the end of a long complicated expression.



Any other ideas out there? All comments welcome.
#15
Anything else we might add? / Extracting comments
July 07, 2007, 10:12:39 AM
I'm looking for some help in designing an algortihm to extract the comment part of a line of LISP code. In particular, I want to write a function "lisp-comment" that will take a line of LISP code in string format and return a list with the code part and comment part separated from each other. For example:



(lisp-comment "(setq a 3) ;we set a variable"))



would return



("(setq a 3)" ";we set a variable"))



At first it seems like you only have to look for the last semicolon and break from there but it is more complicated than that because a semicolon can be inside a string as well as being followed by quoted words. I'm having difficulty determining what the proper rule for finding the right semicolon is. Is there a regex that will do this?
#16
Anything else we might add? / Helpful List Function
June 12, 2007, 07:38:32 PM
One thing I always love about LISP is that it always gets you thinking in ever more general terms after you start out with something simple. Here is a good example of it. My starting point was a one-liner that I wrote that is pretty much self-explanatory:



(define (length? lst n)(= (length lst) n))



Can't get much simpler than that. I don't know how many times I wrote (= (length lst) n) before thinking of it. Just like the paper clip. But what about greater abstraction? What do we do with that length once we get it? I find that I either use it in a control structure to branch the program or I use it in a calculation. Let us just consider the control structure aspect of it. Here is the code first:



(define (iflength lst (n 0) X Y Z , i flg)
  (setq i (length lst) flg (= i n))
  (if Z (if (< i n) X flg Y Z)
      Y (if flg X Y)
      X (if flg X)
      flg
))


So what does iflength do? iflength gobbles up the previous function and acts as a control structure too. Let i be the length of the list, n the number we are comparing to the list, lst the list itself and X,Y,Z are code chunks to be executed depending on how a boolean test is performed. So it goes like this, if we write



(iflength lst n X Y Z) - if i<n then X is executed elseif i=n then Y is executed else Z is executed.

(iflength lst n X Y) - if i=n then X is executed else Y is

(iflength lst n X) - if i=n then X is executed else nothing happens

(iflength lst n)  - behaves the same as the length? function



Very simple, very handy.
#17
I was thinking that it might be nice to add an extra optional argument at the end of the functions FIRST, LAST, NTH, REST and SLICE that represent a value that is to be substituted at that position. So for example



(first "cat") -> "c"

(first "cat" "b") -> "bat"



or



(nth 2 '(2 3 7 77 8) 6) -> '(2 3 6 77 8)



and so on.
#18
Anything else we might add? / Flipping Lists
February 11, 2007, 02:29:30 PM
Take a simple operation like (rest '(a b c d e)) which returns (b c d e). Suppose we wish to get all elements other than the last. We could define the following function:



(define (nrest lst)
   (reverse (rest (reverse lst))))


In LISP we are always looking for higher generalities and we notice the general form (reverse (func (reverse lst))) where func is any operation that we might perform on a list. But we might want to use a function that takes other arguments as well and really want the form



(reverse (func (reverse lst) arg1 arg2 ... argN))



We can define the following function FLIP to do this:



(define-macro (flip)
  (if (= (length (args)) 2)
        (reverse ((eval (args 0))
                  (reverse (eval (args 1)))))
        (reverse (eval (append '((eval (args 0)))
                               '((reverse (eval (args 1))))
                               (slice (args) 2)
                       )))))


Now instead of writing an NREST function we could write our statement as



(flip rest '(a b c d e))



I have found several situations where this double reversal occurs and in most cases this function avoids the need to write special reversal functions. For instance, how about doing a reverse SLICE as in



(flip slice '(a b c d e f g h) 2 3) -> (d e f)



This will only work with functions that take a list as their first argument. Should this be something we should have in the standard toolkit or something like it?
#19
Anything else we might add? / Bit operator defaults
January 16, 2007, 07:33:27 PM
Lutz,



Could we establish these defaults for a couple of the bit operators?



(& n) is the same as (& n 1)

(| n) is the same as (| n 1)
#20
Lutz,



NewLISP currently allows direct numerical input in number bases 8, 10 and 16 with the 0 and 0x prefixes for the binary bases. The integer?, float? and number? functions all return true if you input an octal or hexadecimal base number into them. I ran into a situation where I needed one or more of these functions to return true only for decimal representations. Could we have an extra argument on these functions where the user could specify one or more bases that they wish the function to test for? If no base is specified then all bases are tested for otherwise only the bases listed will be tested. For example:



(integer? n) - all bases tested for

(integer? n 8) - only base 8 integers acceptable

(integer? n '(10 16)) - decimal and hexadecimal acceptable