newLISP Fan Club

Forum => Anything else we might add? => Topic started by: Excalibor on May 29, 2007, 03:20:54 AM

Title: Collect-like and J style
Post by: Excalibor on May 29, 2007, 03:20:54 AM
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/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]
Title:
Post by: Lutz on May 29, 2007, 05:45:46 AM
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).
Title:
Post by: Excalibor on May 29, 2007, 09:22:56 AM
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... :-)
Title:
Post by: Fanda on May 30, 2007, 06:18:11 AM
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
Title:
Post by: Lutz on May 30, 2007, 06:38:04 AM
also instead of:
(do-while (nil? done) ... )

do:


(do-until done ...)

Lutz