This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-01-05
Channels
- # admin-announcements (183)
- # aws (30)
- # beginners (22)
- # boot (301)
- # cider (19)
- # cljs-dev (3)
- # cljsrn (23)
- # clojars (15)
- # clojure (136)
- # clojure-italy (8)
- # clojure-nl (4)
- # clojure-russia (19)
- # clojured (10)
- # clojurescript (134)
- # component (48)
- # cursive (7)
- # datavis (4)
- # datomic (50)
- # devcards (6)
- # events (9)
- # jobs (1)
- # ldnclj (10)
- # lein-figwheel (19)
- # leiningen (1)
- # luminus (16)
- # off-topic (5)
- # om (151)
- # proton (60)
- # re-frame (10)
- # reagent (25)
- # remote-jobs (1)
- # slack-help (3)
- # spacemacs (1)
- # vim (1)
@nogeek: we invented boot partly so we could do transforms on source like that, http://hoplon.io is a cljs dialect that is translated to cljs at build time with a goal of reducing boilerplate
@nogeek: another example, with lein, is https://github.com/ztellman/sleight
@atroche: not exactly - https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LispReader.java#L781
the reader constructs the meta map in there and attaches it to the form, doesn't go through with-meta
I muted #C03RZGPG1, and it's better. The channel won't appear unread, and I'll be notified of mentions of myself only.
@alandipert: very nice will try it out
Hello all. I'm relatively new to Clojure, and am learning by working through Advent Of Code. Anyway, I have a style question, if you don't mind such a newbie question. Which of these two approaches would be more idiomatic / preferable?
(map (partial into []) ["hello" "world"])
or
(map #(into [] %) ["hello" "world"])
thanks.
My money would be on the 2nd. With the 2nd you can see the parameter so it is easier to read.
@dj (map vec ["hello" "world"])
gosh that is nice, thank you also @mikethompson.
@mikethompson: Here's wishing you continued success with re-frame in 2016, btw.
@dj the partial version is apparently the prefered version, according to the style guide, but no good reason was provided
thanks @jethroksy - didn't realise there was one. Found this (assuming it's the one to which you're referring as there's a direct ref to this in it) https://github.com/bbatsov/clojure-style-guide#partial
had a long discussion about this in #C03S1KBA2 a while ago, it ended up as personal preference
@glenjamin: partial will be slower in some cases
not that it matters most of the time, but it might be relevant depending on your usage
I thought the partial speed difference went away in 1.7?
It kind of depends on the context, though. For example, I usually use partial
when the argument that I'm partialing in is some computed value that I don't want to recompute over and over again. Especially if said function is itself going to be passed to some other function as an argument.
partial
doesn't instantiate a new function object like #()
does, but partial
uses varargs and apply
internally for >4args, which is slower
@glenjamin: what @bronsa said
@donaldball: partial was unrolled for <4 args in 1.7
Thanks for the clarification
The original context of these questions is really odd, I just want to add. While valid code, neither example is something I would expect to see in the wild when you can just do (map vec ["hello" "world"])
Bearing in mind the >4 args issue, I see partial as just a way to shorten up an existing function by partialing in early arguments that aren't going to change in the given context.
I tend to just go with (fn [foo bar baz] ...)
unless the #()
form is super easy to understand.
and then you also have the limitation that you can't easily return a vec from the #() form
on the other hand, if the (fn []) version just adds noise then I use #() - its all about clarity
Well, Clojure not being statically typed can't have as nice partial application as Haskell can - partial
is nice and all, but usually when it's not longer to write out than a function.
My first reflex is to use partial
because partial application seems natural to me and then I have to backtrack because it's too verbose.
unless there is a performance issue, to me the act of coding is an act of communication and clarity of the code for both others and my future self is of utmost importance
@jethroksy: I did not know that!
jaen, seriously re: partial application…always disappointed using partial in Clojure. haha
I used to code in Python where "one right way" to do something was what I liked. However, I like Clojure even more and while there does seem to be some amount of personal preference in these things I'm finding that even though I still try to do things one and only one way in Clojure that I need to vary my style of code in order to achieve the clarity and simplicity that I'm after. So these variations aren't a bad thing if handled properly in a variety of contexts.
Thats not the same then, you would have to #(apply f x y %&)
to get the same effect as (partial f x y)
When I first started with Clojure, I found reading fn
s to be clearer to understand than partial
. Mostly because I was unfamiliar with the fns that were being partialed, and because of the explicit argument list in fn. Later, as I've become more skilled with Clojure and I have a good chunk of the std-lib understood, partial seems a lot more straightforward, whereas fn
s seem a bit messy in comparison
no actually partial implements multiple short arities, giving potential performance boosts. Tis bikeshedding for sure!
pkobrien, interesting point. I tend to find that how to implement something in Clojure comes down to exactly what kind of performance characteristics I want along with the shape of the data. I think the whole partial
vs. #()
thing is less common, in general—I don’t often struggle to figure out what the right way to do something in Clojure is.
jaen, re: your previous point it really seems to be less generally applicable, but if you are at all used to the Haskell way of doing things it seems more appealing…it’s just so natural to pass partially applied functions around in Haskell
so I often don’t end up using partial at all in Clojure, because the evaluation strategy is so different
it just feels a lot less idiomatic
Here's a fun use of partial from my code:
(defn rewrite
"Returns a successor, which must be a vector or a function. If no match is
found in the rules mapping, the original module is return within a vector."
[rules m]
(or (rules m) [m]))
(defn rewriting
"Returns a rewriting transducer."
[axiom rules generation]
(map (partial rewrite (get-rewriting-rules axiom rules generation))))
@jethroksy: look at the impl
@ddellacosta: Interesting indeed. I tend to think in terms of the API that I would enjoy using and worry about performance later. And I've only been doing clojure for 8 months with a mostly OO background and no real functional experience so early on it was a real struggle for me.
And here's how much I like into
. Built a whole bunch of uber over it:
(defn produce
"Returns a lazy sequence of colls from a recursive, axiomatic,
transformative process."
[seed prep-f get-xf]
(letfn [(process
[coll]
(lazy-seq
(when (seq coll)
(let [new-coll (into (empty coll) (get-xf coll) (prep-f coll))]
(cons new-coll (process new-coll))))))]
(process seed)))
@ddellacosta: I suppose that's a sensible POV. I'm just probably wishing that you could do something closer to map (* 2)
than to (partial map #(* % 2))
.
@mpenet: We were talking about when you have an indeterminate amount of args to be applied to the partial function
In my mind its the only practical difference, everything else is just clarity/readability/subjective
If its a top-level thing that rarely gets called, that's one thing. But a low-level function that gets called a lot, or will be called using partial or apply == not good.
@jethroksy: got an example?
in clojure, I normally try to consolidate them as maps, and use schema do document the structure. I have a feeling there is probably a better alternative.
Oh, kwargs. Another Clojrue bikeshedding topic. I for one prefer not to use them, since they compose badly.
I think destructing domain values in fn binding forms is a bit of a smell. Unless its literally opts
or config
- I would rather see a noun describing the parameter. And hopefully have as few of these nouns as possible.
if a value ultimately needs to be destructed why not do that in the parameter definition?
@jethroksy: Give me an idea of the domain so I can write an example - what are you adding
an agenda to?
@meow: I suppose he means the fact that the parameter lacks a name, but then again you could always use :as
for documentation I suppose.
I don't think you can generalize - sometimes destructed adds clarity, sometimes it takes it away. No universal rule there imo.
@meow: I agree, thats why I said domain values - the nouns of the program or the datastructures we are operating on and would like to give a name.
I hear what you are saying about domain values. But again, sometimes even with domain values I might want to take the focus off of what is getting passed into the function and just focus on what the function is doing to the bits and pieces and so avoiding using a name actually helps there. For me the rule is always clarity of communication and understanding, not adherence to one style of code.
if you can pass the agenda
straight through there is no point, unless you want the clarity of documentation, arg names etc
the point is it should be clear what a function operates on. Sometimes that really is a map with some set of keys in it. Other times it is a value you are modelling in your domain.
@jethroksy: a map is fine, I am just saying give it a name, and surface that name in your api
so a user (or you in 5 months) can say, "oh that takes an agenda". "These functions operate on agendas" and so on.
@jethroksy: And then maybe a schema Agenda, and a constructor agenda
with a nice docstring.
That is just my personal preference, I gotta go, but hopefully it helps you see things in a different way?
its just one of those build in a few hours, push and forget projects, but i'm not pleased with the way i've gone about it
As god-emperor Rich once said - Nothing much really matters for small programs that will just be hacked out the door and forgotten about
I'm brutal on my own code. I don't often like the code I wrote the day before. But I'm okay with that and expect it. Coding for me is more like writing or art - I expect to do multiple drafts.
I wish I had that liberty: where i work at i'm churning out about 1 slack integration a day
i'm having trouble deciding on the extent to which i should avoid internal state in a library i'm working on. If I have an internal id, that basically serves as a static field that is incremented every time a library operation is performed, is it fine just to define that as a top level atom in the library and increment it whenever the function is called, or is it better to leave that to the user of the library to take care of?
@jjttjj: I think you might run into problems if someone uses your library and e.g. uses some of the namespace reloading tools commonly used for interactive development.
glenjamin: unfortunately i'm depending on a java lib that needs an int for the unique idea
really interesting discussion coming out of the earlier question about partial
vs #(...)
usage - I've learned a lot, thank you. And @meow you are not wrong to comment (https://clojurians.slack.com/archives/general/p1452010834003083) on the oddness of my question - it's mostly due to ignorance on my part, sorry.
@dj: don't be sorry or feel like I was criticizing - just trying to provide some perspective
Although the "100 functions 1 data structure" Perlis epigram has a price - I didn't know (yet) about vec
, or at least had forgotten
@dj: trust me, I've been coding for about 30 years now and learning to think functionally was not an easy switch
I agree. But even at this early stage (for me) it is enlightening and definitely worthwhile.
That's why I jumped on the chance to get a conversation going - it turned out to be a good one.
@jjttjj: two related patterns: * to define the api in a protcol and use a record for state management- so any internal state, like a metric capturing library utilization is a member of the record, and the record is passed in and returned from all api calls * if the need is just for metrics, and these metrics are important for the semantics of the library, consider just building on http://metrics.dropwizard.io/
Here's an example from a different context but it shows one way to increment a counter inside a stateful function:
(defn gen
"Returns a function that, when called, will call f with an incremented
generation number and an additional context data argument."
[f]
(let [generation (volatile! (long -1))]
(fn
[data]
(vswap! generation #(inc (long %)))
(f @generation data))))
Or rather, I hate when library authors store state globally when it doesn't need to be global.