Collect-like and J style

Started by Excalibor, May 29, 2007, 03:20:54 AM

Previous topic - Next topic

Excalibor

Greetings!



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



I am trying the first one, the Collatz conjecture, http://www.jsoftware.com/jwiki/Essays/Collatz_Conjecture">http://www.jsoftware.com/jwiki/Essays/C ... Conjecture">http://www.jsoftware.com/jwiki/Essays/Collatz_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:



(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]

Lutz

#1
Here is a proper recursive solution:


; 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:


; 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).

Excalibor

#2
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:



(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:



> (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... :-)

Fanda

#3
Quote from: "Excalibor"

(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

Lutz

#4
also instead of:
(do-while (nil? done) ... )

do:


(do-until done ...)

Lutz