(archive 'newLISPer)

February 9, 2008

Hello newLISP 9.3

Filed under: newLISP — newlisper @ 16:55

This post should have been uploaded some days ago. I’ve been trying to get round to doing it, but life keeps getting in the way…

The latest version of newLISP, 9.3, is now available, and there are some great new features.

The new when function is going to replace if in a lot of the scripts I’ve written. I’m sure a lot of newLISP users have made the following mistake at least once:

(if expression
   (action1)
   (action2))

where they’re expecting that both actions will be carried out if the expression is true. But with if it’s either the first or the second. The syntax of if requires you to construct a block if you want two or more expressions to be evaluated in sequence:

(if expression
   (begin
      (action1)
      (action2)))

But now there’s when, which will make this form easier to read and write:

(when expression
   (action1)
   (action2))

There are also many new powerful techniques for processing items in nested lists, including set-ref-all. For a great introduction to these, see Jeff’s post at his newly relocated artful code site.

I haven’t managed to prepare a major revision of my Introduction to newLISP for this release, but I tried to include examples of most of the new functions I was able to test. It’s difficult to keep up with newLISP’s pace of development sometimes. But it’s much more interesting to describe a moving target than a static one! As each release adds more powerful functions, some of the examples I wrote last year has been rendered obsolete or – in a few cases – inoperative. For example, my example of writing a macro now provides an unnecessary alternative to the built-in when function.

Apparently, *when* was added to the development builds of newLISP is September 2007, but I never noticed it!

Another function that promises to be one of my favourites is find-all. find-all isn’t a new function – it used to work on strings – but now it works with lists, and with lists of lists (or association lists). It can also, when working with lists, take action expressions and comparison functions.

First, here’s the familiar original form of find-all working on a string:

(set 't {There are 60 seconds in a minute, 60 seconds in an hour, and 24 hours in a day.})
(find-all {\d+} t)
;-> ("60" "60" "24")

Notice that find-all in this form takes regular expressions without you having to tell it to.

Another form of find-all lets you search a list of lists for a list that matches a pattern. You can specify the pattern with wildcard characters. For example, here’s a list of lists:

(set 'symphonies 
  '((Beethoven 9)
    (Haydn 104)
    (Mozart 41)
    (Mahler 10)
    (Wagner 1)
    (Schumann 4)
    (Shostakovich 15)
    (Bruckner 9)))

To find all the lists that end with 9, use the match pattern ‘(? 9), where the question mark matches a single item:

(find-all '(? 9) symphonies)
;-> ((Beethoven 9) (Bruckner 9))

You can also use this form with an ‘action expression’ at the end, after the list:

(find-all '(? 9) symphonies (println (first $0) { wrote 9 symphonies.}))
Beethoven wrote 9 symphonies.
Bruckner wrote 9 symphonies.

Here, the action expression uses $0 to refer to each matched element in turn. If you’ve used replace in newLISP, you’ll be familiar with this idea.

There’s a third form. For searching a plain list, rather than a list of lists, the syntax is different. Supply four arguments: the search key, the list, an action expression, and the functor, which is the comparison function you want to use for matching the search key. This time, don’t use match-style patterns:

(set 'food '("bread" "cheese" "onion" "pickle" "lettuce"))
(find-all "onion" food (print $0 { }) >)
bread cheese lettuce

Here, find-all is looking for the string “onion” in the list food. It’s using the > function as a comparison function, so it will find anything that “onion” is greater than. For strings, ‘greater than’ means appearing later in the default ASCII sorting order, so that “cheese” is greater than “bread” but less than “onion”. Notice that, unlike other functions that let you provide comparison functions (namely find, ref, ref-all, ref-set, replace when used with lists, set-ref, set-ref-all, and sort), the comparison function must be supplied.

With the < function, the result is a list of things that “onion” is less than:

(find-all "onion" food (print $0 { }) <)
pickle

With different comparison functions, and the ability to use an action expression for each ‘successful’ comparison, you can do quite a lot with a single find-all.

Choose a word:

(set 'word "moonstarer")

Select a dictionary. On Unix it’s probably in /usr/share/dict/words; Windows users can probably find something suitable here.

(set 'dictionary (parse (read-file {/usr/share/dict/words})))

Define a test for the anagram-ness of two words:

(define (anagrams? w1 w2)
  (= (sort (explode w1)) (sort (explode w2))))

Then use find-all to look for anagrams of the word:

(find-all word dictionary (println $0) anagrams?)

astronomer

newLISP does all the hard work for you. Notice how the comparison function receives two arguments automatically, one from the list, and the other the contents of *word*. Come to think of it, I don’t need to continually explode and sort the first word, do I?. I’ll leave you to improve it!

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: