(archive 'newLISPer)

December 6, 2007

Adventures in newbie-newLISPland

Filed under: newLISP — newlisper @ 12:27

I’ve been looking through some of my first attempts at programming in newLISP. One thing I noticed was that at first I had trouble working out how to step through a list and process adjacent elements one pair at a time. Come with me now back to newLISP-newbie land!

To reduce the problem to its simplest case, suppose that we want to work through a list looking at each pair of items:

(set 't (sequence 0 13))

0 and 1
1 and 2
...
12 and 13

Solutions are easy to see now, but for some reason I could think only of using dolist or for, which are the more conventional tools for working through lists.

dolist keeps the current position in the list in a system variable $idx, so you can use that to find the next element, given that the loop variable i is the current element.

(dolist (i t)
    (println { processing } i { and }
        (t (+ $idx 1))))

Here, the implicit addressing (t $idx) returns the same element as i, so the next one is obviously (t (+ $idx 1)).

But there’s a trap for the newbie:

processing 0 and 1
...
processing 12 and 13
processing 13 and 13

Helpfully, newLISP won’t crash your scripts just because you overstepped the end of a list, but it definitely is your job to stop processing the list at the right stage.

So let’s add a break condition:

(dolist (i t (= $idx
            (- (length t) 1)))
    (println { processing } i { and }
        (t (+ $idx 1))))

This now stops the loop when the penultimate item in the list has been processed.

How about for? This can also work:

(for (i 0 (- (length t) 2))
    (println { processing }
        (t i) { and }
        (t (+ i 1))))

It’s easy to make mistakes if you’re not concentrating; there are 14 elements in the list; we use index numbers 0 to 13 to get them; with for loops that means stopping at one less than the length; and as we’re doing pairs we stop two before the length.

But there must be a better way. How about using apply?

(apply
    (fn (a b)
        (println { processing } a { and } b)) t 2)

See that last ‘2’. The anonymous function uses two arguments, and the 2 tells apply to use two arguments at a time. It looks like it works nicely:

processing 0 and 1
...
processing 12 and 13

But the newLISP manual says that the result of each application is re-used as the first argument for the next application. What’s happening is that the result of that println expression was the last number evaluated (which was b), and that was also, conveniently enough, the value that we wanted to use as the first number for the next pair.

To see what’s going on, make the lambda function return something else:

(apply
    (fn (a b)
        (string a { and } b)) t 2)

;->
 "0 and 1 and 2 and 3 and 4 and 5 and 6 and 7 and 8 and 9 and 10 and 11 and 12 and 13"

So I think it’s possible to use apply to apply a function to pairs of items if you remember to return the value of the last member of each pair, so that apply can use it for the next pair.

And you could use map:

(map
    (fn (a b)
        (println a { } b))
    (chop t)
    (rotate t -1))

which uses two versions of the list, chopping the end of one and rotating the second. Helpfully, the extra element in the second list is ignored.

More solutions welcome!

Comment from Lutz

… and here is yet another one:

(set 'theList (sequence 0 13))

(dolist (t (explode theList 2 true))
    (println "processing " (t 0) "and " (t 1)))

the ‘true’ flag in the explode expression makes sure that only full pairs are processed if ‘theList’ has an uneven number of elements.

ps: thanks for putting on the Santa theme again ;-)

Comment from newlisper

So suitable for even-length lists…

(I don’t know why Santa deserted the site for a day… :-)

Comment from talk.do.stop

My version (both for odd and even lists):

;newlisp

(map 
  (fn (x y) (println x " and " y)) 
  (0 -1 theList) 
  (rest theList))
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: