NewLisp for VisualNEO Win. Part 5.

This fifth tutorial covers four newLISP topics that could improve your VisualNEO application.


A. Test data again

In Tutorial 2 we put attention to predicates. Predicates are used to test data. Two functions are not categorized under Predicates (www.newlisp.org/downloads/manual_frame.html), but they are very useful: exists and for-all.

1. exists

(setq mc-list ‘(2 “reinier” 1 “hello” 3 8 -1750))
(2 “reinier” 1 “hello” 3 8 -1750)

(list? mc-list)
→ true

(exists string? mc-list)
→ “reinier”

(exists number? mc-list)
→ 2

To check if the number 0 or 0.0 is part of the list:

(exists zero? mc-list)
→ nil

To check if a number of the list is negative:

(exists < mc-list)
→ -1750

Very interesting is the option to add a custom function to ‘exists’. The function

(fn (x) (> x 3))

in the next example checks if a number of the list is greater than 3. The number 8 is the first one.

(setq mc-list ‘(2 1 3 8 -1750))
(exists (fn (x) (> x 3)) mc-list)
→ 8

To check if a number is part of the list:

(exists (fn (x) (= x 10)) mc-list)
→ nil

or a bit easier

(member 10 mc-list)
→ nil

2. for-all
The function ‘for-all’ checks if all elements in a list, meet the condition of a function. The result is true or nil.

(for-all number? ‘(2 1 3 8 -1750))
→ true

(for-all number? ‘(“Bach” 2 1 3 8 1750))
→ nil

(for-all (fn (x) (= x 1750)) ‘(1750 1750 1750 1750))
→ true

(for-all (fn (x) (= x 1750)) ‘(1685 1750))
→ nil

The command (fn (x) (= x 1750)) is a so called anonymous function (see the next section B).


B. Custom functions
You can define a function. As example, the function sum:

(define (sum x y) (add x y))

You can invoke the function as follows:

(sum 2 3)
→ 5

More interesting is the anonymous function which you can use in iteration situation (see next section C)

(fn (x y) (add x y))

This function can be called e.g. in the for-all function, as you saw in the previous section. More examples:

(define double (fn (x) (+ x x)))
(double 2)
→ 4

(apply (fn (x) (+ x x)) ‘(123))
→ 246

(set ‘db ‘((a 3) (g 2) (c 5)))
(sort db (fn (x y) (>= (last x) (last y))))
→ ((c 5) (a 3) (g 2))

(setq mc-list ‘(“Maeve” “Olivia” “Aurora” “Ada” “Charlotte” “Amara”))
(find “Isla” mc-list (fn (x y) (> (length x) (length y))))
→ 3   ; “Isla” is longer than element 3, “Ada”

(map (fn (x) (pow 2 x)) (sequence 1 10))
→ (2 4 8 16 32 64 128 256 512 1024)

To make your code more readable, you could assign the function to a variable:

(setq mc-pow2 ‘(fn (x) (pow 2 x)))
(map mc-pow2 (sequence 1 10))
→ (2 4 8 16 32 64 128 256 512 1024)

This demonstrates what you can read in newLISP and Lisp texts: source code and data are interchangeable. Really, a wonderful feature!


C. Iteration

NewLISP has several interation functions. The functions do-until, do-while, doargs, dolist, dostring and dotimes can be useful for you. But let’s have a short look at the function ‘for’.

Its normal use is:

(for (x 1 10 1) (print x))
→ 12345678910

or with now step 2

(for (x 1 10 2) (print x))
→ 13579

or with now step 0.5

(for (x 3 2 0.5) (print ” – ” x))
→ 3 – 2.5 – 2

But very nice is the option to add some break condition to the ‘for’ command:

(for (x 1 100 2 (> (* x x) 30)) (print ” – ” x))
→ 1 – 3 – 5


D. Processing power

Sometimes you need to speed up your VisualNEO application, e.g. in case of nested loops. Well, newLISP is your friend. What I did not tell you is that VisualNEO can easily communicate with extensive newLISP scripts. The idea is: pass variables to the newLISP script.

Suppose, you have an application with a text entry object ‘User’. The contents of this text entry object are stored in the VisualNeo variable [mcText]. Users enter their long text. You want to process that text with newLISP. Readable newLISP oneliners are now not possible. How to manage this? Solution: you have only to pass [mcText] to the newLISP code. In a few steps, I’ll explain this to you.

Step 1
Make a second text entry object ‘Code’ with your newLISP source code (position it outside your application window).
The contents of this text entry object are stored in the variable [mcNewLISP-code].

Step 2
Determine the length of user’s text with StrLen:

StrLen “[mcText]” “[mcTextLen]”

Step 3
Add to the a second text entry object ‘Code’ the following commands:

(setq mcStringLen (nbget “[mcTextLen]” 255))
(setq size (int mcStringLen))
(setq mcString (nbget “[mcText]” size))

or in one string:

(setq mcString (nbget “[mcText]” (int (nbget “[mcTextLen]” 255))))

Step 4
Invoke hpwNewLISPCall in your VisualNEO application:

hpwNewLISPCall “[mcNewLISP-code]” “[DllRetvar]”

[DllRetvar] will return the result.

You could also store the result in a separate file. Add to the newLISP code the following at the end:

(setq mcOutputFile (replace “\\” (nbget “[Outputfile]” 255) “/”))
(write-file mcOutputFile mcString)

The VisualNeo variable [Outputfile] could be defined as:

SetVar “[Outputfile]” “[PubDir]temp.txt”

newLISP code will run very fast which enhances your VisualNEO application.


Debugging

It can be handy in case of debugging to set a VisualNEO variable with some newLISP values, i.e. an intermediate result:

(nbset “[CheckVar]” (string mcString ))


E. Conclusion

This was my last tutorial on newLISP and VisualNEO. I hope that it was helpful for you. I think that you will have enough information to continue the newLISP-VisualNEO journey by yourself. Thank you for reading my tutorials.

Reinier Maliepaard

(last update: 08-12-2019)