Fork me on GitHub
#clojure
<
2016-10-19
>
amacdougall02:10:32

I have a problem here that seems like it should have a straightforward solution, but I guess it is so straightforward that I can't see it. Given a map such as {:a 1 :b 2 :c 3}, how can I return the key whose value is highest?

amacdougall02:10:18

Everything I can think of involves messing around with max and vector indices, which seems way too complicated.

amacdougall02:10:16

Great... I was looking at the documentation for https://clojuredocs.org/clojure.core/min-key, which is far more abstruse.

bfabry02:10:28

(there are so many crazy random functions in core that are seriously hard to remember)

amacdougall02:10:33

There should be a law that documentation examples have to cover the most common cases first!

bfabry02:10:35

crazy useful random functions

amacdougall02:10:48

Sometimes I think it would be neat to have a job doing Clojure full time on a team. Then I look at code people actually write, and I don't feel nearly smart enough.

amacdougall02:10:42

(let [m {:a 1 :b 2 :c 3}]
  (apply max-key val m))
I'm having a hard time grasping how this works, in fact. I know that val gives the value of a map entry such as [:a 1].

amacdougall02:10:30

And m, in the context of apply, becomes a vec of map entries, right? [[:a 1] [:b 2] [:c 3]].

amacdougall02:10:00

Ah, I guess val is the "key" here... max-key actually lets you use any function, as far as I can tell.

amacdougall02:10:26

So it figures out a max by using val as the key of each map entry.

bfabry03:10:31

lol, yes, it's the maximum or minimum object as determined by the key function. equivalent to (last (sort-by or (first (sort-by

bfabry03:10:40

I think the name is probably related to a use case like (max-key :balance [{:user-id 1 :balance 1}{:user-id 2 :balance 2}])

bfabry03:10:41

and yeah, when a map is in the last position in an apply call, the map becomes a sequence of map entries

bfabry03:10:19

(note it's equivalent to but much more efficient than the sort-by variants, because doesn't build up an interim list)

jrheard04:10:26

@amacdougall - re: finding functions, check out this utility that comes with your repl:

user=> (apropos "max")
(clojure.core/max
 clojure.core/max-key
 clojure.core/ref-max-history
 clojure.core.rrb-vector.rrbt/max-extra-search-steps
 io.aviso.columns/max-length
 io.aviso.columns/max-value-length)
i have literally never used it, but every so often i remember it exists and am like “why have i never used this"

jrheard04:10:36

(you give it a string like “url”, “file”, etc, and it gives you back any functions whose name seems relevant)

danielgrosse09:10:22

When I want to call a different function for different regex-matches, is cond a good solution? E.g.

(cond
  (re-matches #"1" 1) (callfunc 1)
  (re-matches #"2" 1) (callfunc 1))

dominicm09:10:16

@danielgrosse I'd say so!

mccraigmccraig09:10:43

macro question - is there a fn i can use to transform the arg of a macro so that it has namespace qualified symbols - so i can use the forms as part of an eval later ?

dominicm09:10:30

At a guess, I might say resolve

mccraigmccraig09:10:51

@dominicm resolve returns vars... and would require consideration around special-forms (resolve 'if) => nil which i was hoping already exists 🙂

dominicm09:10:48

Ah, unsure then.

fellshard10:10:38

(condp #(re-matches %2 %1) x
  #"1" (callfunc 1)
  #"2" (callfunc 2)
  ... )
Something like that maybe?

fellshard10:10:25

Better matches the fact that the predicate and queried object don't change, just the cases by which the queried object is compared.

dominicm10:10:27

@fellshard That feels like a "clever" solution, I personally found the first one easier to understand.

fellshard10:10:07

Maybe? That's usually the type of case condp is used for

dominicm10:10:25

However, I can understand with a large number of such cases why it might be necessary.

fellshard10:10:28

Fixed predicate, fixed expression

fellshard10:10:00

And yeah, the more expressions, the cleaner it'll be. Small number of expressions, might not be worth the effort

dominicm10:10:04

To me, there is mental overhead to parsing the predicate. And for 2/3 cases, not something that's really worth it.

hans10:10:15

I find that the condp solution is easier to read.

fellshard10:10:43

Would be handy if there were a flip there instead of an anonymous func, too

fellshard10:10:56

(flip re-matches)

fellshard10:10:22

But that's a BYOF at minimum added value

hans10:10:33

fellshard: not generic enough, as it'd apply only to functions with two arguments.

dominicm10:10:41

Maybe it's the %X args I am struggling with in myself.

fellshard10:10:22

Yeah. condp that's the expectation at least, since the predicate is supposed to take two args, but not sure about re-matches.

fellshard10:10:19

Would be neat if regexes implemented IFn, maybe with re-matches. Could see it as being a 'no obvious default' case, though

Yehonathan Sharvit14:10:48

Is there a convenient way to “read” a .cljc file as :cljs?

Yehonathan Sharvit14:10:08

I mean to see the output of the reader according to :cljs or :clj?

danielgrosse14:10:44

I want to create a default object with some values. The title has later to be extended with a number. I now use a

(def element
{:name #(fn [nr] (str "name-" nr))
:height 120
}
)
How could I call the function when I use the element later? Or is there a better way to do this?

danielgrosse14:10:56

I want to do something like

(merge element {:width 200})

dpsutton14:10:37

are you sure you want the object to have the function to update its name?

dpsutton14:10:47

would you rather not assoc the name later when the number is known?

dpsutton14:10:13

(assoc element :width 200)

danielgrosse14:10:37

But when I want to assign multiple values at once?

exupero15:10:55

Can you describe the problem you’re trying to solve? It’s a bit hard to guess what you want.

dpsutton15:10:00

assoc allows for multiple keys

dpsutton15:10:10

(assoc mapping e1 v1 e2 v2 ...)

danielgrosse15:10:39

I want to create structures, which are then converted to xml. The elements have some default values, which are always the same, and some which I have to calculate at the generation. The nodes have to have a unique name, but for further handling, I assign them a common name and extend it with a number. e.g. element-title-1 element-title-2 element-body-1 element-body-2

dpsutton15:10:32

so you want a function that creates a default object which takes some parameters, and then you assoc on top

dpsutton15:10:15

`(let [obj (get-default-object param1 param2)] (assoc obj key1 val1 key2 val2 )`

dpsutton15:10:31

or you could mess with threading macros if you knew other things

dpsutton15:10:38

or you could pass a map of stuff

dpsutton15:10:11

(create-object name value1 value2 {:other-keys "value" :other-key "another value"})

dpsutton15:10:57

and in this situation, just assoc each key in the map at the end onto the object you are creating

danielgrosse15:10:44

Okay, thank you. I will think about it.

dpsutton15:10:20

and if you need unique auto-generated numbers, an easy way to do that is to have a single atom holding a counter and then increment it and return that value

exupero15:10:34

I’ve also used gensym for generating IDs.

mpenet15:10:05

gensym is nice for this , but it wont hold across restarts

dpsutton15:10:27

oh nice. i wasn't aware that you could give it a prefix

verma15:10:43

I just UUID for such things

mpenet15:10:46

I think it calls intern tho, so might not be a good idea for "serious" stuff

mpenet15:10:54

yeah uuid is the way to go

idiomancy15:10:56

Is there like a "clojure master class" style workshop that occurs anywhere in the US? I know clojure conj is coming up, but thats more like the future of the language.

danielgrosse15:10:00

Thank you all for your tips. 👍

idiomancy15:10:18

I think my current weakness is that I'm a solid data manipulator, but a lot of the "metagame" of clojure is pretty highly developed, like how to optimize your workflow/repl development, how to make the attribute level the most important aspect of your programming, how to get the most out of core.spec, etc

dpsutton15:10:31

well, there's one specifically on core.spec, but the rest are either intro or datomic

idiomancy15:10:17

huh. The intro course will probably have one or two things I could benefit from. And the other two courses look good. I'd be shelling out a decent amount to hit them all though

idiomancy15:10:44

The spec one and the datomic ones would be the best bang per buck

jrheard15:10:22

@idiomancy have you watched previous years’ conferences’ talks online?

jrheard15:10:31

there’s lots of great stuff in there

idiomancy15:10:53

Yeah, clojure conj is beautiful stuff

jrheard15:10:08

see also strange loop, clojure/west, etc (there’s one or more european conferences too)

idiomancy15:10:21

the tricky thing is the "I dont know what questions to ask" problem

idiomancy15:10:03

I want someone who has had experience in industry clojure to curate a list of things that separate a powerful, professional clojure workflow from a "clojure immigrant"

idiomancy15:10:27

because I definitely still feel like a clojure immigrant.

alexmiller15:10:17

@viebel you can invoke either the reader (in Clojure) or tools.reader with a specified feature set (which specifies the platform). (read-string {:read-cond :allow :features #{:clj}} “(your-form)”) is the idea in Clojure’s reader, although the Clojure reader will forcibly add the platform feature so you won’t really get the cljs result properly. But you can do that with tools.reader which is slightly different to invoke but similar.

dpsutton15:10:23

best thing to do is look back on your mistakes.

dpsutton15:10:33

And the best way to do that is do a lot of things and make some mistakes

idiomancy15:10:25

Yeah, and I agree there, for certain. Which is actually what prompts the question

alexmiller15:10:14

@viebel and in fact, reading a file using tools.reader with :features #{:cljs} is exactly what ClojureScript does. https://github.com/clojure/clojurescript/blob/176c681b25b75e907bf376698263dacf6ce998f4/src/main/clojure/cljs/analyzer.cljc#L3098

alexmiller15:10:46

@idiomancy we get asked about “master class” type things at Cognitect all the time but in general when we dig in more we find that people are interested in widely divergent topics that are entirely dependent on what they are actually building. that is, they really want someone on-site to pair / assess / guide so we often end up doing that kind of an engagement instead. the intro class we do at the conj is a pretty good overview of a good percentage of the language you’ll actually use.

idiomancy15:10:39

Huh, that makes sense. I would kill for clojure mentorship

idiomancy15:10:51

but I mean, thats what you guys are for hahaha

alexmiller15:10:18

I am a co-author of Clojure Applied and our goal there was to convey how to take you from “I understand the syntax” to “I can apply this language to solve problems”. So that is my best answer there. :)

idiomancy15:10:22

Well then, that sounds like the way to go

alexmiller15:10:28

however, re your topics it does not cover repl workflow (which is both constantly changing and highly individualized in my experience so a poor topic for a book) or spec (which didn’t exist yet). I am working on a new edition of Programming Clojure which will have a full chapter covering spec plus some additional integration throughout the text (but don’t expect that soon)

idiomancy15:10:58

Well, I'll try to attend your class

idiomancy15:10:07

if theres still room

alexmiller15:10:19

please do! I think it is pretty full but still has some spots.

idiomancy16:10:17

oh, congrats on snagging the edgiest functional programming twitter handle I've ever seen

idiomancy16:10:24

thats awesome

jrheard16:10:57

lol i’ve seen that handle floating around for years and just now got the relevance to functional programming

gfredericks16:10:34

what? is it just the word "pure"?

jrheard16:10:12

that’s my interpretation, yeah

jrheard16:10:22

all this time i thought he was just like really into danger?

idiomancy16:10:21

i mean, I dont want to overanalyze this, but its the association between "pure" fp and danger, like disruptive tech. You know, like, the fp revolution? I mean I dont think that's really the intention, but it kind of works

idiomancy16:10:10

Again, I dont think its worth fixating on, its just clever.

gfredericks16:10:51

P. U. Redanger

Yehonathan Sharvit16:10:01

@alexmiller is there a command lime tool (or web app) that reads cljc files?

idiomancy16:10:46

P.U. - RE: danger

idiomancy16:10:58

he thinks danger is smelly.

verma16:10:30

@viebel kind of like planck may be? https://github.com/mfikes/planck

alexmiller16:10:49

@viebel and does what?

alexmiller16:10:26

@jrheard the handle pre-dates by years me ever doing anything with FP and I had not ever thought of that :)

seancorfield16:10:37

@idiomancy He talks about it a bit on https://defn.audio/2016/10/06/episode-11-alex-miller/ (puredanger)

alexmiller16:10:11

but I don’t anymore

seancorfield16:10:29

That is a truly awesome domain name 😸

alexmiller16:10:40

used to host my blog there

Yehonathan Sharvit17:10:55

@alexmiller returns the :clj content or the :cljs.

Yehonathan Sharvit17:10:08

It might be useful for debugging

jrheard19:10:22

what’s the best way to find a clojure sticker for eg a laptop?

jrheard19:10:36

i live in portland OR if that’s relevant

lvh19:10:24

I think I got mine at Clojure/west.

jrheard19:10:39

aha - nice, thx

jrheard19:10:05

i’ll buy a sheet of 20 and give the rest to the local meetup group 🙂

andreas-thoelke19:10:19

Hi! I'm trying to use case with type like this:

andreas-thoelke19:10:41

.. which doesn't work. What's the proper way to do this?

brabster19:10:04

@alexmiller I heard you talking about puredanger,com on defn and I remembered having your blog on my rss catcher back in the day! I can see now why you've not had time to continue writing it! 👍 simple_smile

exupero19:10:43

@andreas-thoelke Try (condp = (type ch) …)

andreas-thoelke19:10:09

@exupero hmm, but with condp, how would I do the third condition in my example? (list of matching items)

jr19:10:15

(condp contains? (type ch) and then use a set for each test

andreas-thoelke19:10:17

contains? is for map keys, I think?

jr19:10:34

works for set as well

jr19:10:53

user=> (contains? #{1 2 3} 2)
true
user=> (contains? #{1 2 3} 4)
false

andreas-thoelke19:10:26

You mean like this:

alexmiller20:10:29

@brabster I write stuff at http://insideclojure.org occasionally, or also on the Cognitect blog http://blog.cognitect.com/?author=53c6f0c5e4b0c2fe7d81be34

timgilbert22:10:34

Hi all, got a question on (with-redefs): is there any way for me to get at the value of the redefined var? My specific use case is that inside of some tests, I want to return mock data from a function for some specific inputs to it, but if the inputs aren't in that special set I want to call the original function

timgilbert22:10:49

...and the calls themselves might be way down on the call stack and can be hard to predict. So what I'd like to do is something like (with-redefs [ns/foo (fn [x] (if (= x :specific-thing) :mock-data (ns/foo x)))] ...(test code)... )

timgilbert22:10:53

...but I worry that the second invocation of (ns/foo) will just recur into the redefined fn and blow the stack

hiredman22:10:03

well, just use let

hiredman22:10:32

(let [orig ns/foo] ...)

hiredman22:10:48

call orig instead of ns/foo where you want the original value

jey23:10:09

hi, what's the recommended way in leiningen to handle a project that has multiple subprojects? for instance, I have a clojurescript client application (mobile app) and a server-side webapp (api server). is lein-sub a good choice?