This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-09-10
Channels
- # admin-announcements (1)
- # beginners (109)
- # boot (59)
- # cljs-dev (1)
- # clojure (101)
- # clojure-android (1)
- # clojure-denmark (4)
- # clojure-france (1)
- # clojure-japan (5)
- # clojure-russia (39)
- # clojurescript (186)
- # clojurex (3)
- # clojutre (2)
- # cursive (20)
- # datomic (6)
- # devops (6)
- # events (3)
- # hoplon (25)
- # jobs (1)
- # ldnclj (5)
- # off-topic (4)
- # reagent (3)
- # ring (2)
I'm pretty sure this doesn't need to be written as a tail call recursion because of the use of lazy-seq.
I just worked on some code that uses lazy-seq in a similar fashion and if you look at the source code for clojure core you will see quite a bit of use of lazy-seq this way.
When you look at the use of lazy-seq in the source for clojure you have to sort of ignore all the testing for chunks, but partition
doesn't have any chunk optimizations going on so its a pretty good example of what I'm describing: https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L3051
@paulb: I think (not= [] coll)
will always be true - (seq coll)
is the idiomatic test for an empty collection as it will return nil
not the case, actually, but I would still use seq
:
(def baz [1 2 3])
=> #'user/baz
(not= baz [])
=> true
(def foo [])
=> #'user/foo
(not= foo [])
=> false
I mostly agree with what's been said. seq is surely the idiomatic way to check for empty-ness. I wonder why it works better from a performance standpoint
@escherize: I'm going to guess that it's a datatype issue and that with the larger coll given on the website that the type of coll is being changed under the covers by clj and then (not= [] coll)
is returning true
even though it is empty
@meow: That could be the case, esspecially given:
(map (partial not= []) [#{} {} [] '()])
;;=> (true true false false)
@escherize: it's actually really simple:
(not= [] (seq []))
=> true
(type (seq []))
is kind of dumb because (seq [])
returns nil
so that's the same as asking (type nil)
but you get my point...
sets, maps, and sequential collections are each "equality partitions" and won't compare as equal
calling seq produces a seq from any of them, pulling all of them into the sequential collection equality partition
seq is not (necessarily) the fastest way to check for emptiness - really depends on the scope of what you are checking (whether you are potentially checking for any collection or just a counted collection, etc)
@alexmiller: got a minute for a stateful transducer question?
I have a process and in one step I want to check an item to see if it is a list (that's just a convention I've chosen) and if so, it needs to have two elements, the first is like any other item and the second is extra parameter data of some kind that I want to store separately, so I'm storing it in a map as state in the enclosing function, like this:
(defn split-module-params-xf
"Returns a stateful transducer that accumulates a map of module parameters,
where the key is the index position of the module in the resulting word."
[]
(fn [rf]
(let [data (volatile! {})
index (volatile! 0)]
(fn
([] (rf))
([result] (rf result [@data]))
([result input]
(let [v (vec (for [[n, module] (map-indexed vector input)]
(if (list? module)
(let [[module param] module]
(vswap! data assoc (+ @index n) param)
module)
module)))]
(vswap! index + (count v))
(rf result v)))))))
I need to keep this extra parameter data stored separately from the module, to keep things simple for the consumer of this process.
Plus this data is optional and I can be processing millions of items so I need an efficient storage.
seems ok I guess
The only gotcha is I allow additional transducers to be supplied and if one downstream removed an item then this data map would be screwed.
for is going to construct a lazy seq which you then put into a vector
you could make a vector directly by replacing (vec (for ...)) with mapv
it's just hard for me to understand the scope of what's being done
its my L-system code, revised to be transducerized to the max: https://github.com/decomplect/ion/blob/master/src/ion/ergo/l_system.cljc#L256-L274
or instead of mapv, you could nest another transducer operation using (into [] ...)
you could then chain map-indexed with the operation with the inner map operation?
does map-indexed have a transducer arity?
oh, yeah. I wrote it. :)
so many patches :)
so this is a rewriting system that I've coded, so typically the replacement value has more items than what is being replaced, which is why I use that inner map-indexed
you're creating vectors for every element of input when you don't know yet whether or not it is a list so it seems like you are potentially doing speculative work there
input will always be a vector, what I don't know yet is whether the item in that vector is a list
oh right, but you always need that vector regardless, so never mind
if you're really trying to squeeze perf out of that inner loop, I would think about ways to refactor to avoid the destructuring via either reduce or loop/recur
to state my problem more generally, I need an effective way to associate parameters with replacement values - I just made up the idea of using a list, since it isn't a commonly used datatype, with a pair of values
are they always pairs?
and the second element can be anything, and certainly you can do a lot with a map or nested maps
for very specialized cases, then you could use a defrecord or a custom deftype that implemented the needed interfaces
with records, you'd be constructing small objects and using field accessors, which is highly optimized on the JVM
I will note that the pair has to be stored in something unique, because an item without this parameter data could be a 2-element vector, for example
yeah, you get a type too of course so that's useful
It also needs to be easy for the writer of the "grammar" or replacement rules to specify these replacements
like this:
(defn parametric-contextual-system-example
[]
(let [axiom ['(:A {:age 0})]
rules {:A (fn [g w d i m]
['(:B {:age 0})
:-
(list m {:age (inc-age d i)})
:-
'(:B {:age 0})])
:B (fn [g w d i m]
['(:A {:age 0})
:+
(list m {:age (inc-age d i)})
:+
'(:A {:age 0})])}]
(parametric-contextual-system axiom rules)))
(comment (take 5 (parametric-contextual-system-example)))
if you had (defrecord P [a b]), then you'd just replace list above with ->P
there's actually an example of creating a Pair deftype in Clojure Applied, by the way
well, I may be biased, but I agree :)
I'd really recommend buying 5 or 10 and giving them away
you could put them under chair legs too
or use them as a paperweight
just saying
as far as my trick of tacking on the @data map at the end of the transducing process, is that reasonable?
my parametric process then looks like this:
(letfn [(process [w d]
(lazy-seq
(when (seq w)
(let [result (transduce (get-xf) (get-rf) w)
word (butlast result)
data (peek result)]
(cons [word data] (process word data))))))]
(process jumpstart {}))))
and if I make the parameter splitting always come after any user-specified transducers (comp (f-xf) (split-module-params-xf))
then I don't have to worry about a downstream transducer messing up the indexing.
@alexmiller: tyvm for all the help - I really appreciate it.
Hello everyone. I have question
I use RabbitMQ, and write little worker which use it
I start it via
lein run -m workers.yandex-market
am I should make .jar, .war file for it? Or should execute from source
There will be more workers later
Worker's code has been placed here https://gist.github.com/sergeylaptev/7cac391846d44b2fdbd1
@sergeylaptev: This article is for webapps written in Clojure, but you could adapt this for your RabbitMQ workers. http://adambard.com/blog/deploying-a-clojure-web-app-on-digitalocean/
am I should compile every worker as dedicated .jar?
If you had to deploy your workers to a lot of servers, I think it would be convenient to have one .jar file to copy around.
Both worker and my app with compojure use "generate-yml" function
Are they can use it after decoupling?
As I understood, all my workers will be dedicated in separate repo, and compiled into one .jar?
Or 1:1?
I would put the workers and your web app in different repos. You'll have to make your generate-yml function available to both somehow.
I learn Clojure about 2 weeks, and can't understand this schema:)
Any better way to create a function to return and return a collection of a number of things?
(defn make-sample-data [how-many]
(take how-many (repeatedly #(g/generate ApiResult))))
g/generate
is prismatic schema creating a map
oh cool!
(defn make-sample-data [how-many]
(repeatedly how-many #(g/generate ApiResult)))
thanks