Nathan Sorenson | 1 Oct 2010 01:33
Picon
Picon
Favicon

Any clean way to avoid explicit recursion when creating nested loops?

I was discussing this on the clojure channel, and it seems as though
avoiding explicit recursion is the idiomatic thing to do. Is there a
better way to define a function that loops over an arbitrary number of
sequences in a nested fashion, similar to the 'for' macro, without
relying on recursion?

This is the current approach, using recursion:

(defn nested [& seqs]
  "returns lazy 'for'-like nesting of a seq of seqs."
   (letfn [(nestrec [prefix [list & deeper-lists]]
                  (if deeper-lists
                     (mapcat #(nestrec (conj prefix %) deeper-lists)
list)
                     (map #(conj prefix %) list)))]
      (nestrec [] seqs)))

so (nested (range) [:a :b]) returns [[0 :a][0 :b] [1 :a] [1 :b]
[2 :a] ... ]

--

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure <at> 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+unsubscribe <at> googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

(Continue reading)

Mark Engelberg | 1 Oct 2010 01:55
Picon

Re: Any clean way to avoid explicit recursion when creating nested loops?

clojure.contrib.cartesian-product does what your nested function does,
but more efficiently, using iteration rather than recursion.

--

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure <at> 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+unsubscribe <at> googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Steven E. Harris | 1 Oct 2010 02:07
Picon
Favicon
Gravatar

Re: Idiomatic Way to Build String or Simply Use StringBuilder

Mark Engelberg <mark.engelberg <at> gmail.com> writes:

> str uses a string builder behind the scenes, so it's efficient this
> way.

If the `str' implementation didn't take the input sequence to be lazy,
it could figure out how long the resulting string needed to be, and
construct the StringBuilder using the single-integer constructor,
ensuring that no reallocation and copying occurs. Some temporary
allocation would still be necessary to hold the Object-to-String
projection, as `str' calls Object#toString() on each argument, rather
than assuming the arguments are already of type String.

-- 
Steven E. Harris

--

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure <at> 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+unsubscribe <at> googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Nathan Sorenson | 1 Oct 2010 02:29
Picon
Picon
Favicon

Re: Any clean way to avoid explicit recursion when creating nested loops?

That's perfect, thanks!

On Sep 30, 4:55 pm, Mark Engelberg <mark.engelb... <at> gmail.com> wrote:
> clojure.contrib.cartesian-product does what your nested function does,
> but more efficiently, using iteration rather than recursion.

--

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure <at> 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+unsubscribe <at> googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Phil Hagelberg | 1 Oct 2010 03:07
Gravatar

Calling macros by var

So I noticed some curious behaviour:

    (defmacro foo [body] {:env &env :form &form :body body})
    => #'user/foo

    (#'user/foo :body)
    => java.lang.IllegalArgumentException: Wrong number of args (1)
passed to: user$foo (NO_SOURCE_FILE:0)

    (#'user/foo :form :env :body)
    => {:env :env, :form :form, :body :body}

    (#'user/foo :form :env body)
    => Unable to resolve symbol: body in this context

So it appears when you call a macro by its var, it acts just like a
function, even though its metadata says it should be a macro.

    (:macro (meta #'foo))
    => true

I suspect the answer may just be "yeah... that's not something you
should do with macros", but I'm curious. I suppose the compiler only
checks the :macro metadata when it's literally in the call position
rather than when there's indirection through calling var?

-Phil

--

-- 
You received this message because you are subscribed to the Google
(Continue reading)

Sean Corfield | 1 Oct 2010 04:09
Picon
Gravatar

Re: Problems Running tests with fixtures

On Thu, Sep 30, 2010 at 2:44 PM, Timothy Washington <twashing <at> gmail.com> wrote:
> Just in case anyone comes across this, I did get around it. In fig. 2 I was
> trying to run (use-fixtures) twice. One with a :once, and one with :each.

I just tried that and it worked fine for me:

(ns utest)
(use 'clojure.test)
(defn f [x] (println "f before") (x) (println "f after"))
(use-fixtures :each f)
(defn g [x] (println "g1")(x)(println "g2"))
(use-fixtures :once g)
(deftest test-me (is ( = 1 1)))
(deftest test-me-2 (is ( = 2 2 )))
(run-tests)

Produced:

Testing utest
g1
f before
f after
f before
f after
g2

Ran 2 tests containing 2 assertions.
0 failures, 0 errors.
{:type :summary, :pass 2, :test 2, :error 0, :fail 0}

(Continue reading)

HiHeelHottie | 1 Oct 2010 05:37
Picon

Re: Idiomatic Way to Build String or Simply Use StringBuilder


Everybody, thanks for all your responses.  conj to vector feels good
so that's what I'm playing with now.  Michael, in answer to your
question, and this may be more detail than you bargained for, I'm
playing around with a little state machine parser.  It actually
doesn't do much now, but baby steps as I learn clojure.  Eventually, I
want it to make distinctions between numbers that pass through and
numbers that are transformed.  Am not crazy about having to add a
space at the end of the original string and welcome edifying comments.

(ns test-test.parse
  (:use [clojure.contrib.string :only (split)]))

(defn parse-char [m c]
  (condp = (:state m)
      :degree (cond
               (Character/isDigit c) (assoc m :degree (+ (* (:degree
m) 10) (Character/digit c 10)))
               (Character/isWhitespace c) (assoc
m :state :whitespace :buf (conj (:buf m) (:degree m) " ") :degree 0))
      :whitespace (cond
                   (Character/isDigit c) (assoc
m :state :degree :degree (+ (* (:degree m) 10) (Character/digit c
10)))
                   (Character/isWhitespace c) m)))

(defn parse [s]
  (let [m (reduce parse-char {:state :degree :degree 0 :buf []} (str s
" "))]
    (apply str (:buf m))))
(Continue reading)

ataggart | 1 Oct 2010 06:13
Picon
Gravatar

Re: Clojure 1.3 alpha 1 report - bitwise operations extremely slow

As with most microbenchmarks you're measuring the test more than the
subject.  In the above case the seq generation dominates.

Compare the following on my machine:
user=> (time (doseq [x (range 100000)] (bit-shift-left x 1)))
"Elapsed time: 3531.198 msecs"
nil
user=> (time (dotimes [x 100000] (bit-shift-left x 1)))
"Elapsed time: 3.744 msecs"
nil

Beyond the seq issue there is a further (very small) penalty due to
seqs working with objects, thus x from the range seq is a Long object,
not a primitive long.  You can see the implementation differences of
shiftLeft here:
http://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Numbers.java#L425

On Sep 29, 11:19 pm, Mark Engelberg <mark.engelb... <at> gmail.com> wrote:
> bitwise-and and bitwise-shift-right and bitwise-shift-left run more
> than 50 times slower in clojure 1.3 alpha 1 versus clojure 1.2.  Could
> the 1.3 gurus please investigate this?
>
> Try something like this to see the difference:
> (time (doseq [x (range 100000)] (bit-shift-left x 1)))
>
> This points to another issue with Clojure 1.3.  I can't figure out how
> to determine what is a primitive and what isn't.  Are the values
> produced by range primitives?  Are the values produced by bitwise
> operations primitive?  How can I determine this?

(Continue reading)

Mark Engelberg | 1 Oct 2010 06:52
Picon

Re: Clojure 1.3 alpha 1 report - bitwise operations extremely slow

On Thu, Sep 30, 2010 at 9:13 PM, ataggart <alex.taggart <at> gmail.com> wrote:
> As with most microbenchmarks you're measuring the test more than the
> subject.  In the above case the seq generation dominates.
>
> Compare the following on my machine:
> user=> (time (doseq [x (range 100000)] (bit-shift-left x 1)))
> "Elapsed time: 3531.198 msecs"
> nil
> user=> (time (dotimes [x 100000] (bit-shift-left x 1)))
> "Elapsed time: 3.744 msecs"
> nil

But if you replace the bit-shift-left operation with some other
arithmetic operation in the doseq expression, it is quite fast, thus
disproving your assertion that the slowdown is caused by the overhead
of doseq.  Furthermore, as we've already discussed, type hinting the x
or removing the inline delcaration from bit-shift-left makes the
problem go away -- inside the doseq expression.

So, if it is true that range produces objects and dotimes produces
primitive longs, then I believe that it is the odd interaction between
bit-shift-left's inlining and long objects (as opposed to primitives)
that is causing the disparity in your measurements, not something
inherent in the mechanism of doseq vs dotimes.

--

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure <at> googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
(Continue reading)

Sean Corfield | 1 Oct 2010 07:57
Picon
Gravatar

Re: Changing keys in a map

On Thu, Sep 30, 2010 at 12:52 AM, David Sletten <david <at> bosatsu.net> wrote:
> Huh?! How many solutions do you want? You're starting to annoy me Sean.

Sorry dude. I think it's really insightful to see lots of different
solutions to small point problems like this when you're learning a
language - particularly when the issue of idiom is being discussed.
I've certainly found this thread educational and I hope I'm not
annoying too many people :)

Things I'm finding particularly helpful:
* into / for
* comp vs #() vs ->
* split a map and zip it vs a single pass with a more complex function

The into / for thing was great because it's something that seems very
Clojurish that I wouldn't have thought of without input.

I'm very excited about Clojure. I think it's going to be core to my
team's work over the next couple of years. I haven't been able to do
serious functional programming for about three decades but Clojure
really provides that option. We're already using Scala for certain
performance-critical pieces of our system but it's not a language that
I can present to most of my web developers - they're used to dynamic
scripting languages, no type system, no compile/deploy/run cycle.
--

-- 
Sean A Corfield -- (904) 302-SEAN
Railo Technologies, Inc. -- http://getrailo.com/
An Architect's View -- http://corfield.org/

"If you're not annoying somebody, you're not really alive."
(Continue reading)


Gmane