Greetings, Clojurers!

I've been playing with clojure, particularly with lazy sequences.
Some of the
results have left me puzzled, so I saved a REPL session wherein I
illustrate the points
of puzzlement.  REPL lines are indented below; added comments are
unindented.


    Clojure 1.2.1

I define a silly version of "even?" which uses a lazy sequence:

    user=> (defn ev? [n] (nth (cycle [true false]) n))
    #'user/ev?

It works, albeit slowly, for large arguments:

    user=> (time (ev? 9876543210))
    "Elapsed time: 337225.287 msecs"
    true

This won't work, if any reference is retained to that long sequence:

    user=> (def ev-stream (cycle [true false]))
    #'user/ev-stream
    user=> (defn ev? [n] (nth ev-stream n))
    #'user/ev?
    user=> (time (ev? 9876543210))
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap
space
        at java.lang.reflect.Method.copy(Method.java:143)
        at java.lang.reflect.ReflectAccess.copyMethod(ReflectAccess.java:118)
        at sun.reflect.ReflectionFactory.copyMethod(ReflectionFactory.java:
282)
        at java.lang.Class.copyMethods(Class.java:2748)
        at java.lang.Class.getMethods(Class.java:1410)
        at clojure.lang.Reflector.getMethods(Reflector.java:310)
        at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:27)
        at clojure.main$repl_caught.invoke(main.clj:116)
        at clojure.main$repl$fn__5637.invoke(main.clj:206)
        at clojure.main$repl.doInvoke(main.clj:204)
        at clojure.lang.RestFn.invoke(RestFn.java:421)
        at clojure.main$repl_opt.invoke(main.clj:262)
        at clojure.main$main.doInvoke(main.clj:355)
        at clojure.lang.RestFn.invoke(RestFn.java:397)
        at clojure.lang.Var.invoke(Var.java:361)
        at clojure.lang.AFn.applyToHelper(AFn.java:159)
        at clojure.lang.Var.applyTo(Var.java:482)
        at clojure.main.main(main.java:37)

    Process scheme exited abnormally with code 1

Okay, that was the expected java.lang.barf.  No puzzlement so far.
Now I restart the REPL.

    Clojure 1.2.1

Once again, I make a globally referenced, infinitely long stream.  But
now I use "lazy-seq"
instead of "cycle":

    user=> (def ev-stream (lazy-seq (cons true (cons false ev-
stream))))
    #'user/ev-stream
    user=> (defn ev? [n] (nth ev-stream n))
    #'user/ev?
    user=> (time (ev? 9876543210))
    "Elapsed time: 47244.061 msecs"
    true

OMG! Not only did it NOT hose the heap and crash, it actually ran much
faster than the version
with the unreferenced "(cycle [true false])".

The only reason I can think of, for this to NOT exhaust memory, is
that the lazy-seq macro knows
when to construct a circular list. Is that what happens?  If so, why
DOESN'T it happen with "cycle",
where it's obviously the behavior one would want?

Okay, now I'll play the same game again, but with "mod 3":

    user=> (def mod3-stream (lazy-seq (cons 0 (cons 1 (cons 2 mod3-
stream)))))
    #'user/mod3-stream
    user=> (defn mod3 [n] (nth mod3-stream n))
    #'user/mod3

It passes a simple test:

    user=> (map mod3 (range 20))
    (0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1)

It passes a test with a pretty big number:

    user=> (time (mod3 987654321))
    "Elapsed time: 28998.966 msecs"
    0
    user=> (mod 987654321 3)
    0

Now I'll test it with 9876543210, a number which "ev?" was able to
handle:

    user=> (time (mod3 9876543210))
    "Elapsed time: 37759.615 msecs"
    1
    user=> (mod 987654321 3)
    0

Whoa! The computation finished in reasonable time, but with the WRONG
answer! How did that happen?
Did I find a bug?

Thanks for reading this far, and best regards,

George Kangas

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to