together with repeatedly:
(take-while pred (repeatedly f)))
Sincerely
Meikel
> --~--~---------~--~----~------------~-------~--~----~
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> To unsubscribe from this group, send email to clojure+u...@googlegroups.com
> For more options, visit this group at http://groups.google.com/group/clojure?hl=en
> -~----------~----~----~----~------~----~------~--~---
>
(pred) does not depend on (f)? Is there some IO or mutable state?
--
Professional: http://cgrand.net/ (fr)
On Clojure: http://clj-me.blogspot.com/ (en)
lazy-seq to the rescue:
(defn mouse-seq
[]
(lazy-seq
(when (Mouse/hasEvent)
(cons (Mouse/getEvent) (mouse-seq)))))
Sincerely
Meikel
Am 07.05.2009 um 23:54 schrieb CuppoJava:
> But don't you find:
>
> (for [:while (Mouse/hasEvent)] (Mouse/getEvent))
>
> much shorter and easier to understand?
Actually: no. I think of for as a way to transform
a sequence, not constructing a completely new
one. There are constructs like iterate and repeatedly
for that. If they are not sufficient, one can drop to
lazy-seq. (And sometimes dropping to lazy-seq
can yield clearer code than some contorted
map filter concat map combination)
In fact I think the lazy-seq version is pretty self-explaining.
On the other hand I should use for more often.
So maybe this view is all wrong. YMMV in the end.
Sincerely
Meikel
Hi,
This `lazy-seq` over a `when` and `cons` idiom seems fairly common. Is
there any reason there is not a function for it? For example:
(defn cons-while
"Lazily creates a sequence by repeatedly calling f until pred is
false"
[pred f]
(lazy-seq
(when pred
(cons f (cons-while pred f)))))
I haven't tested it but I suspect the following should now work:
(cons-while (Mouse/hasEvent) (Mouse/getEvent))
I think a facility like this is part of the underpinning of functional
reactive programming (FRP), which is an active research area in
designing interactive systems such as GUIs functionally rather than
object orientedly (if that's a word).
Consider a trivial demo where you want to continuously update the
mouse's coordinates in a text box on a window. You could just map a
function which updates that text box across the potentially infinite
list of mouse events. Yes, it would block until the next event came
in, but the UI is in a consistent state while the mouse isn't moving.
One has to assume that sequences of events are potentially infinite.
Haskell is pretty good at the infinite list part, but it's pretty bad
at the side-effect part and timing part. I tried pretty hard to read
Conal Eliot's paper "Simply Efficient FRP" <http://conal.net/papers/simply-reactive/
> but I never got far enough in Haskell to actually understand what
it's saying. It looks like something hard to do in Haskell.
It's also been done in Scheme, specifically the FrTime "language" in
DrScheme. There's a paper about it here: <http://citeseer.ist.psu.edu/cache/papers/cs/32750/ftp:zSzzSzftp.cs.brown.eduzSzpubzSztechreportszSz03zSzcs03-20.pdf/cooper04frtime.pdf
> which I haven't even tried to read.
There's also an interesting Javascript implementation called Flapjax,
which was pretty under-documented when I heard about it, but makes it
a little easier to get the gist of the idea: <http://www.flapjax-lang.org/
>
From what little I have gathered about the concept, Clojure ought to
be in a unique position to leverage it, since Clojure has ready access
to both GUI frameworks and lazy sequences from within an easy-to-
reason-about strict language. Much of the work in Haskell FRP must be
to cope with state and time, whereas in other languages it must be to
introduce the right kinds of laziness and parallelism. Clojure has a
good mixture of these ingredients already.
There could be extremely novel ways of approaching well-known problems
hiding within Clojure right now.
—
Daniel Lyons
http://www.storytotell.org -- Tell It!
Am 09.05.2009 um 13:06 schrieb Mark Reid:
> ; ---- Begin lazyread.clj ----
> (import '(java.io FileReader BufferedReader PrintWriter))
>
> (def filename "test.data")
>
> ; Write out a small test file. Numbers 0 to 99, one per line.
> (with-open [data (PrintWriter. filename)]
> (dotimes [i 100] (.println data i)))
>
> ; An attempt at capturing the general idiom that doesn't work
> (defn cons-while
> [pred f]
> (lazy-seq
> (when pred
> (cons f (cons-while pred f)))))
> ; ---- End lazyread.clj ----
There is a mistake in this function: pred should be (pred)
as well as f should be (f).
Furthermore I would call it repeatedly-while.
(defn repeatedly-while
[pref f]
(lazy-seq
(when (pred)
(cons (f) (cons-while pred f)))))
Then this should work:
(repeatedly-while #(.ready reader) #(.readLine reader))
I didn't test it, though.
Sincerely
Meikel
Thanks,
Mark.
Am 10.05.2009 um 07:19 schrieb Laurent PETIT:
> No problem, but you can still consider (for the definition of the
> function) the equivalent higher-order version I provided later in
> the my post (you didn't answer to this one):
>
> (defn repeatedly-while [no-arg-pred f]
> (take-while (fn [ _ ] (no-arg-pred) f))
>
> whose usage is the same as Meikel's one,
This is not equivalent to my version. The calling site
looks the same, but it still consumes one element of
the seq before evaluating the predicate. That is the
way take-while works. But it doesn't help in the given
reader example, since you read before checking,
whether the reader is actually ready...
Sincerely
Meikel
Am 10.05.2009 um 07:00 schrieb Mark Reid:
> So the extra parentheses are there to force the evaluation of the
> predicate and function?
Well. The don't "force" the evaluation. They just call the provided
function. "pred" evaluates to a function. In our example #(.ready
reader).
"(pred)" simply call this function. As "(repeatedly-while pred f)"
calls the
function named by "repeatedly-while" passing the functions named by
pred and f as arguments. I wouldn't call this "forcing"...
Sincerely
Meikel