Page 1 of 1

Collect-like and J style

Posted: Tue May 29, 2007 10:20 am
by Excalibor
Greetings!

LTNS, actually... I'm unrusting myself with an interesting page I found, essays in J language ( http://www.jsoftware.com/jwiki/Essays ).

I am trying the first one, the Collatz conjecture, http://www.jsoftware.com/jwiki/Essays/C ... Conjecture , and I was wondering how do you do in idiomatic newlisp the kind of collect that's displayed there, which is a kind of fold operation:

"apply function recursively and accumulate the results until it returns nil..."
"

I haven't really thought a lot about it yet, and my first attempt, which I offer below, is pretty naive, although it works...

anyone up to discuss about this?

thanks!

PS- the code:

Code: Select all

(context 'collatz)

(define (collatz1 n)
  (if (<= n 1)
	nil
	(if (= (mod n 2) 0)
	  (/ n 2)
	  (+ 1 (* 3 n)) ) ) )

(define (collatz:collatz n)
  (let ((ret '()))
	(do-while (> n 1)
		(setq n (collatz1 n))
		(push n ret -1) )
	ret ) )

(context 'MAIN)

> (collatz:collatz 9)
(28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1)
[/code]

Posted: Tue May 29, 2007 12:45 pm
by Lutz
Here is a proper recursive solution:

Code: Select all

; recursive solution
(define (collatz n)
    (let (result '())
        (if (= n 1)
            (append result '(1))
            (begin
                (set 'k (if (= (% n 2) 0)
                    (/ n 2)
                    (+ 1 (* 3 n))))
                (set 'result (cons n (collr k)))))))

(collatz 9) =>
(9 28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1)
but the link doesn't really describe it as a recursive solution and an iterative is about 3 times faster and shorter too:

Code: Select all

; non-recursive solution
(define (collatz n)
    (let (result (list n))
        (do-until (= n 1)
            (set 'n (push (if (= (% n 2) 0)
                        (/ n 2)
                        (+ 1 (* 3 n))) result -1)))
        result))

(collatz 9) =>
(9 28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1)
the result sequence should also contain the first value

Lutz

ps: good to see you here Excalibor (for those who do not know, Excalibor contributed the orginal Vi syntax file).

Posted: Tue May 29, 2007 4:22 pm
by Excalibor
Lutz,

thanks for the help, it was pretty, well, helpful... :-)

Below I provide a 'collect' function that does kind-of foldr as I'd like to...

crude, but it could be useful:

Code: Select all

(define (collect f n)
  (let ((done false) (result (list n)))
    (do-while (nil? done)
      (begin
        (setq n (f n))
        (if (nil? n)
          (set 'done true)
          (push n result -1) ) ) )
  result ) )
This allows to write:

Code: Select all

> (collect collatz:collatz1 9)
(9 28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1)
which is kinda nice... :-)

anyway... it looked like an interesting problem to try in different environments, the article goes on with pretty interesting stuff (even if J is almost like line-noise!)...

thanks again!
dwd

PS- maybe a macro would be more useful, but I'm not really sure... If the function returns nil as it's 'termination' value, it's okay this way, but things better converge rather fast, or the stack would be smashed... anyway, it works for the time being... :-)

Posted: Wed May 30, 2007 1:18 pm
by Fanda
Excalibor wrote:

Code: Select all

(define (collect f n)
  (let ((done false) (result (list n)))
    (do-while (nil? done)
      (begin
        (setq n (f n))
        (if (nil? n)
          (set 'done true)
          (push n result -1) ) ) )
  result ) )
Just a note: there is no 'false' in newLISP - use 'nil' in (done false).

Fanda

Posted: Wed May 30, 2007 1:38 pm
by Lutz
also instead of:

Code: Select all

(do-while (nil? done) ... )
do:

Code: Select all

(do-until done ...)
Lutz