Re: Non-tail recursion (Clojure way to hierarchies)

2010-06-16 Thread Quzanti
Thanks James.

If any one else is as new to functional stuff as me then I found this
in Paul Graham's book which enables me to reason logically about the
matter (hopefully)

A good compiler can compile a tail call into a goto, and so can
compile a tail recursive function into a loop. In typical machine
language code, when control arrives for the first time at the segment
of instructions representing len (a local fn) there is information on
the stack saying what to do upon returning. Because nothing remains to
be done after the recursive call, this information remains valid for
the second call as well

On Jun 15, 11:28 pm, James Reeves jree...@weavejester.com wrote:
 On 15 June 2010 22:56, Quzanti quza...@googlemail.com wrote:

  Thanks Mike.

  So does is the only kind of recursion optimisation tail recursion?

  Can you only eliminate stack calls in tail calls?

 No, you can also eliminate stack calls using lazy-seq or trampolines.

 If you provide some example code of what you are currently doing, it
 would be easier to gauge what is the most suitable approach.

 You might not even need to bother eliminating stack calls, if you know
 you're never going to recurse very far.

  Having some sort of hint about this in the recur documentation might
  be helpful?

 Well, the docs do say recur in other than a tail position is an
 error, though that does assume the reader knows what the tail
 position of a function is.

 - James

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


Re: Non-tail recursion (Clojure way to hierarchies)

2010-06-15 Thread Oleg
I've looked at tree-seq and can say that is not suitable for non-tail
children tasks.
For example how can i attach subtotal row to bottom of each level. Any
ideas?


On 13 июн, 16:35, Andrzej ndrwr...@googlemail.com wrote:
 On Sun, Jun 13, 2010 at 7:35 PM, Oleg oleg.richa...@gmail.com wrote:

  Currently i'm just calling function, but there is a danger of
  StackOverflow. I can't use recur, because it's not last statement. As
  i can understand recur is good to build long sequences, but in my case
  i'm building hierarchy.

 Two potential solutions:
 1. Build a lazy hierarchy, i.e. instead of returning a nested
 structure, return a function that produces it. It might be better to
 use a built-in function tree-seq though (check the implementation of
 file-seq and xml-seq).
 2. If everything else fails use a 
 trampolinehttp://groups.google.com/group/clojure/browse_frm/thread/6257cbc4454b...

 Cheers,

 Andrzej

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


Re: Non-tail recursion (Clojure way to hierarchies)

2010-06-15 Thread Mike Meyer
On Tue, 15 Jun 2010 03:24:08 -0700 (PDT)
Quzanti quza...@googlemail.com wrote:

 You can use recur to build a hierarchy. What do you mean by you can't
 use it as it is not the last statement?

Exactly that. recur in some sense terminates the current call, and
hence is required to be the last statement in the call.

 I have used recur in all sorts of places in the fn, without noticing
 any restrictions, and built hierarchies.

The restriction is temporal, not spatial. You can put the recur
statement anywhere you want, but there must be no other function
waiting on it's return value. Or, if it weren't a special form, then
it's value would be the value of the function.

So this is legal, with the recur as the last function both temporally
and spatially:

(defn counter [n  result]
  (if (zero? n)
 result
 (recur (dec n) (conj result n

And moving the recur spatially still works:

(defn counter2 [n  result]
  (if ( n 0)
 (recur (dec n) (conj result n))
 result))

But if we invert the conj and recur, so that conj uses the result of
the recur, it breaks at compile time, even if the recur is spatially
the last statement in the function:

(defn busted-counter [n]
   (if (zero? n)
  []
  (conj (recur (dec n)) n)))

You can, of course, write this as  a conventionally recursive function:

(defn recursive-counter [n]
   (if (zero? n)
  []
  (conj (recursive-counter (dec n)) n)))

But this version *isn't* tail recursive - it'll use up n levels of
stack.

Personally, I like recur. Telling the language I believe this is a
tail recursive call means it can tell me I was wrong at compile time,
rather than after it runs out of stack out run time. I hope it stays
around after we get TCE.

   mike
-- 
Mike Meyer m...@mired.org http://www.mired.org/consulting.html
Independent Network/Unix/Perforce consultant, email for more information.

O ascii ribbon campaign - stop html mail - www.asciiribbon.org

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


Re: Non-tail recursion (Clojure way to hierarchies)

2010-06-15 Thread Chouser
On Sun, Jun 13, 2010 at 8:39 AM, Oleg oleg.richa...@gmail.com wrote:
 Thank you, but could you provide me a little code snippet which will
 iterate through collection and assoc children key for each row.

 On 13 июн, 16:35, Andrzej ndrwr...@googlemail.com wrote:
 On Sun, Jun 13, 2010 at 7:35 PM, Oleg oleg.richa...@gmail.com wrote:

  Currently i'm just calling function, but there is a danger of
  StackOverflow. I can't use recur, because it's not last statement. As
  i can understand recur is good to build long sequences, but in my case
  i'm building hierarchy.

 Two potential solutions:
 1. Build a lazy hierarchy, i.e. instead of returning a nested
 structure, return a function that produces it. It might be better to
 use a built-in function tree-seq though (check the implementation of
 file-seq and xml-seq).

I think a lazy hierarchy is the way to go, but tree-seq is a way
to walk a tree, not build one.

For a real example of a lazy hierarchy, you can look at
clojure.contrib.lazy-xml, which builds a lazy tree of XML nodes.
But it may be hard to learn from without getting lost in SAX API
craziness, so here's an attempt at a simpler example:

First, a function to return some children for a given parent:

(defn children [parent]
  (vec (map + (repeat (* 10 parent)) (range 10

(children 42)
;= [420 421 422 423 424 425 426 427 428 429]

Note this is a vector and thus non-lazy, just as in your problem
description.

Now we want a function that returns a tree node for a given item.
For this example a node will be just a map with an :item and
a lazy sequence of :kids:

(defn node [item]
  {:item item
   :kids (map node (children item))})

The fact that 'map' is lazy is critical here.  If we force that
map when creating a node, our first call to 'node' will force the
whole tree and could have unbounded recursion.  But 'map' is lazy
so we know that a single call to node will be O(1).  Only when we
actually realize the :kids seq will 'children' be called.

We can now build a tree and look something up in it:

(- (node 0) :kids (nth 3) :kids (nth 5) :kids (nth 8) :item)
;= 358

So this is an infinitely deep tree that we can navigate without
any actual recursion, just as we can walk an infinite lazy seq
without recursion, and thus there's no threat that the stack will
overflow:

(:item (reduce #(nth (:kids %1) %2)
   (node 0)
   (take 5000 (cycle (range 10)
;= 123456789012345678...67890123456789

Note that since these trees are infinitely deep, a depth-first
walk like tree-seq does is probably not very useful:

(take 8 (map :item (tree-seq :kids :kids (node 1
;= (1 10 100 1000 1 10 100 1000)

Hope that helps!

--Chouser
http://joyofclojure.com/

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


Re: Non-tail recursion (Clojure way to hierarchies)

2010-06-15 Thread Quzanti
Thanks Mike.

So does is the only kind of recursion optimisation tail recursion?

Can you only eliminate stack calls in tail calls?

Having some sort of hint about this in the recur documentation might
be helpful?

On Jun 15, 2:32 pm, Mike Meyer mwm-keyword-googlegroups.
620...@mired.org wrote:
 On Tue, 15 Jun 2010 03:24:08 -0700 (PDT)

 Quzanti quza...@googlemail.com wrote:
  You can use recur to build a hierarchy. What do you mean by you can't
  use it as it is not the last statement?

 Exactly that. recur in some sense terminates the current call, and
 hence is required to be the last statement in the call.

  I have used recur in all sorts of places in the fn, without noticing
  any restrictions, and built hierarchies.

 The restriction is temporal, not spatial. You can put the recur
 statement anywhere you want, but there must be no other function
 waiting on it's return value. Or, if it weren't a special form, then
 it's value would be the value of the function.

 So this is legal, with the recur as the last function both temporally
 and spatially:

 (defn counter [n  result]
   (if (zero? n)
      result
      (recur (dec n) (conj result n

 And moving the recur spatially still works:

 (defn counter2 [n  result]
   (if ( n 0)
      (recur (dec n) (conj result n))
      result))

 But if we invert the conj and recur, so that conj uses the result of
 the recur, it breaks at compile time, even if the recur is spatially
 the last statement in the function:

 (defn busted-counter [n]
    (if (zero? n)
       []
       (conj (recur (dec n)) n)))

 You can, of course, write this as  a conventionally recursive function:

 (defn recursive-counter [n]
    (if (zero? n)
       []
       (conj (recursive-counter (dec n)) n)))

 But this version *isn't* tail recursive - it'll use up n levels of
 stack.

 Personally, I like recur. Telling the language I believe this is a
 tail recursive call means it can tell me I was wrong at compile time,
 rather than after it runs out of stack out run time. I hope it stays
 around after we get TCE.

        mike
 --
 Mike Meyer m...@mired.org          http://www.mired.org/consulting.html
 Independent Network/Unix/Perforce consultant, email for more information.

 O ascii ribbon campaign - stop html mail -www.asciiribbon.org

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


Re: Non-tail recursion (Clojure way to hierarchies)

2010-06-15 Thread James Reeves
On 15 June 2010 22:56, Quzanti quza...@googlemail.com wrote:
 Thanks Mike.

 So does is the only kind of recursion optimisation tail recursion?

 Can you only eliminate stack calls in tail calls?

No, you can also eliminate stack calls using lazy-seq or trampolines.

If you provide some example code of what you are currently doing, it
would be easier to gauge what is the most suitable approach.

You might not even need to bother eliminating stack calls, if you know
you're never going to recurse very far.

 Having some sort of hint about this in the recur documentation might
 be helpful?

Well, the docs do say recur in other than a tail position is an
error, though that does assume the reader knows what the tail
position of a function is.

- James

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


Re: Non-tail recursion (Clojure way to hierarchies)

2010-06-15 Thread Raoul Duke
On Tue, Jun 15, 2010 at 3:28 PM, James Reeves jree...@weavejester.com wrote:
 Well, the docs do say recur in other than a tail position is an
 error, though that does assume the reader knows what the tail
 position of a function is.

see, for example, @tailrec in scala.

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


Non-tail recursion (Clojure way to hierarchies)

2010-06-13 Thread Oleg
Hello Guys!

Here is the task:

Assume that we have function called `fetch-from-source`, which used to
fetch vector of maps from the data source. I want to make iteration on
every fetched row (element of vector) and ask `fetch-from-source`
again to add 'children' key to that row. And so on, until given
depth.

So i want to use map function on collection from some function `expand-
groups`, which will call the same function `expand-groups` on every
collection element to assign children on it. Keep in mind, that the
map function is not last in my function, because i have to append one
more row to mapped collection.

Currently i'm just calling function, but there is a danger of
StackOverflow. I can't use recur, because it's not last statement. As
i can understand recur is good to build long sequences, but in my case
i'm building hierarchy.


What do you think guys? Is there are clojure-rish way to solve that
problem?

Cheers, Oleg

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


Re: Non-tail recursion (Clojure way to hierarchies)

2010-06-13 Thread Andrzej
On Sun, Jun 13, 2010 at 7:35 PM, Oleg oleg.richa...@gmail.com wrote:

 Currently i'm just calling function, but there is a danger of
 StackOverflow. I can't use recur, because it's not last statement. As
 i can understand recur is good to build long sequences, but in my case
 i'm building hierarchy.

Two potential solutions:
1. Build a lazy hierarchy, i.e. instead of returning a nested
structure, return a function that produces it. It might be better to
use a built-in function tree-seq though (check the implementation of
file-seq and xml-seq).
2. If everything else fails use a trampoline
http://groups.google.com/group/clojure/browse_frm/thread/6257cbc4454bcb85/7d5fd827cd549080#7d5fd827cd549080

Cheers,

Andrzej

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


Re: Non-tail recursion (Clojure way to hierarchies)

2010-06-13 Thread Oleg
Thank you, but could you provide me a little code snippet which will
iterate through collection and assoc children key for each row.

On 13 июн, 16:35, Andrzej ndrwr...@googlemail.com wrote:
 On Sun, Jun 13, 2010 at 7:35 PM, Oleg oleg.richa...@gmail.com wrote:

  Currently i'm just calling function, but there is a danger of
  StackOverflow. I can't use recur, because it's not last statement. As
  i can understand recur is good to build long sequences, but in my case
  i'm building hierarchy.

 Two potential solutions:
 1. Build a lazy hierarchy, i.e. instead of returning a nested
 structure, return a function that produces it. It might be better to
 use a built-in function tree-seq though (check the implementation of
 file-seq and xml-seq).
 2. If everything else fails use a 
 trampolinehttp://groups.google.com/group/clojure/browse_frm/thread/6257cbc4454b...

 Cheers,

 Andrzej

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