Fork me on GitHub
#clojure
<
2017-12-12
>
lmergen07:12:43

so i notice that my code has this pattern around quite a bit

(if (some? x)
 (do-stuff x)
 x)
what's the idiomatic way to address this more elegantly ? am i simply oblivious to a function that exists for this ?

dominicm08:12:50

Your else case always returns nil here I guess, so there's that.

lmergen08:12:26

yeah i think i gave a bit wrong example

dominicm08:12:53

http://clojuredocs.org/clojure.core/when-some This is useful if there's an expression involved

lmergen08:12:03

i think this better illustrates the pattern:

(if (condition x)
  (do-stuff x)
  x)

lmergen08:12:25

i ended up rewriting this as

(cond-> x
 (condition x)
 (do-stuff))

dominicm09:12:47

Yeah, I find myself doing that a lot, don't like it either.

dominicm09:12:43

There's a macro by a JUXTer called condas-> which solves this a little I think.

dominicm13:12:55

I actually just wrote this code for a coercer.

lmergen07:12:34

i guess

(some-> x do-stuff)
does the trick ?

hagmonk08:12:12

some? returns true if its argument isn't nil … depends on whether you really care about nil or logical false. If logical false is ok:

(when x
  (do-stuff x))
also works

hagmonk08:12:51

it will return nil in the case where the test doesn't return logical true, so be aware of that ...

martinklepsch09:12:19

Struggling to get clj / tools.deps to work, getting: Error building classpath. Unknown coordinate type for org.clojure/clojure: {:type :mvn, :version "1.8.0"} Anyone know why that could be?

pesterhazy09:12:18

@martinklepsch what's your command line?

pesterhazy09:12:38

and your deps.edn?

martinklepsch09:12:48

@pesterhazy just clojure or clj. I do have a deps.edn which contains this:

{:deps
 {clj-time {:mvn/version “0.14.2”}}}

pesterhazy09:12:05

does it work from an empty directory?

martinklepsch09:12:09

(which is copied from the guide)

martinklepsch09:12:29

same error in empty directory

pesterhazy09:12:31

is it the latest version? (`brew upgrade clojure`)

martinklepsch09:12:54

I did reinstall / make sure it’s up to date

pesterhazy09:12:04

what's the output of clojure -Sverbose

pesterhazy09:12:12

(also which clojure)

pesterhazy09:12:31

check the files in

config_paths = /usr/local/Cellar/clojure/1.8.0.193/deps.edn /Users/me/.clojure/deps.edn deps.edn

pesterhazy09:12:40

you may need to delete ~/.clojure

martinklepsch09:12:56

that was it, thanks!

pesterhazy09:12:01

:information_desk_person:

martinklepsch09:12:34

I looked for the user config but didn find it (thought I never created one so probably just didn’t look hard enough)

martinklepsch09:12:02

Would be nice if the error indicated which file the error comes from

pesterhazy09:12:33

The config is an overlay of the 3 edn files laid on top of each other, so this might be difficult

pesterhazy09:12:18

But maybe it could say "Error: ... - the config files used were x, y and z"

martinklepsch09:12:11

yeah I guess that would already be a good improvement

martinklepsch09:12:15

@pesterhazy do you know if the clj command does any preprocessing of the deps.edn file?

martinklepsch09:12:58

(tools-deps/resolve-deps (read-string (slurp "deps.edn")) {})
trying this but getting Unknown coordinate type for clj-time: #:mvn{:version “0.14.2”}

martinklepsch09:12:06

just running clj works fine

pesterhazy09:12:56

is it because of the overlay effect I mentioned?

pesterhazy09:12:06

Try using this instead:

(->> "/usr/local/Cellar/clojure/1.9.0.273/deps.edn /Users/me/.clojure/deps.edn deps.edn" split-by-space (map slurp) (map read-string) (apply merge))

pesterhazy09:12:20

(pseudo-code)

pesterhazy09:12:36

not sure how that explains the error message though

pesterhazy09:12:43

not sure then

martinklepsch09:12:49

FWIW all files seem to be using the same syntax as my local deps.edn

pesterhazy09:12:30

There's #tools-deps as well btw - Alex is hanging out there

qqq12:12:46

(defn vec->map [v]
  (into {} (reverse  (for [[i k] (keep-indexed vector v)]
                    [k i]))))

(vec->map [:a :b :a :d])
(comment
 {:d 3, :a 0, :b 1})


is there a builtin for this/ it builds a map of "first of index" for each value

mbjarland14:12:07

@qqq

(vec->map [:a :b :c])
=> {:c 2, :b 1, :a 0}
(zipmap [:a :b :c] (range))
=> {:a 0, :b 1, :c 2}
but I assume I'm missing some aspect of the requirement here?

schmee14:12:02

@mbjarland that will give you the last index instead of the first if you have duplicates in the array

mbjarland14:12:21

ah, ok just saw the second :a

schmee14:12:06

here’s my variation:

(reduce (fn [m [i k]] (if (get m k) m (assoc m k i))) {} (map-indexed vector [:a :b :a :d]))

mbjarland14:12:24

you could still go zipmap:

(defn f[v]
    (zipmap (reverse v) (reverse (range 0 (count v)))))

schmee14:12:52

that will be slow if you have large sequences though

mbjarland14:12:01

how about:

(defn f[v]
    (zipmap (rseq v) (range (dec (count v)) -1 -1)))
? rseq is constant time, range is fast as it's bound and not explicitly reversed etc

mbjarland15:12:00

a simplistic bench seems to put them more or less on equal footing, though it seems that rseq is picky and <edited>only lkes vectors and sorted maps</edited>:

(def my-v (mapv (comp keyword str) (range 1000000)))
=> #'user/my-v

(defn f[v]
    (zipmap (rseq v) (range (dec (count v)) -1 -1)))
=> #'user/f

(defn g [v]
  (reduce (fn [m [i k]]
            (if (get m k)
              m
              (assoc m k i)))
          {}
          (map-indexed vector v)))
=> #'user/g

(take 2 (time (f my-v)))
"Elapsed time: 504.559267 msecs"
=> ([:821597 821597] [:323982 323982])

(take 2 (time (g my-v)))
"Elapsed time: 744.353442 msecs"
=> ([:821597 821597] [:323982 323982])

schmee15:12:48

neat benchmark!

schmee15:12:05

can you give it a shot with a transient map for the reduce version?

tbaldridge16:12:27

Might also consider using reduce-kv:

(reduce-kv assoc
           {}
           [4 3 2 1])

nha16:12:13

I am trying to extend a Java class (add a new method) and call a private method of that class inside it. I tried with proxy, I can override an existing method (not a new one) - but can’t seem to access this in the overridden code. Is gen-class my only option?

tbaldridge17:12:06

With this sort of OOP gook, it's often better to write your code in Java and then call that via Clojure.

tbaldridge17:12:18

Or use gen-class, but that's rather hard to get right

tbaldridge17:12:14

@nha if you go the java route, I highly suggest trying this lein plugin: https://github.com/ztellman/virgil it autoreloads Java classes when the .java files change. Makes playing with Java/Clojure interop a lot faster.

nha17:12:48

Appreciate the advice, thanks 😄 (yeah gen-class doesn’t look like the most welcoming bit of Clojure)

bronsa17:12:30

yeah stay away from gen-class

bronsa17:12:25

there's https://dev.clojure.org/jira/browse/CLJ-1255 which would help in most cases where people now reach for proxy/gen-class

bronsa17:12:07

if you care, vote for it

noisesmith17:12:49

it’s an option to define a protocol with the method you want to implement, then proxy the class and also that protocol

nha17:12:33

yes the real problem is access to this private methods (overriding an existing method is fine, performance is not a problem) I am actually considering a thin separate Java wrapper library now

nha17:12:24

I would probably have used CLJ-1255 if it was there already - so will upvote even though I can’t comment on the actual implementation (EDIT - will upvote once I find my login back)

nha17:12:35

Thanks all 😄

hiredman17:12:38

bronsa: do you think you could write that as a macro and release it as a library outside of core?

bronsa17:12:48

it's not worth it tho

bronsa17:12:04

I mean, the current impl reuses half Compiler.java

bronsa17:12:14

I really don't have it in me to reimplement it

nha17:12:33

(I must admit I eyed the patch to check if it was self-contained in a ns 😛 )

bronsa17:12:13

but yeah, I've thought about it

royaldark17:12:22

anyone have insight into this behavior? I am really at a loss here

royaldark17:12:26

=> (do (defrecord Foo []) Foo)
user.Foo
=> (identity (do (defrecord Bar []) Bar))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: Bar in this context, compiling:(null:1:10) 

bronsa17:12:18

it's commonly called the gilardi scenario

royaldark17:12:24

ahhh interesting. That's a very helpful link, thanks!

bronsa17:12:59

tl;dr: clojure's compilation unit is the top level form, the compiler explodes top level dos and treat them as N compilation units. From within a single compilation you don't see the effects of runtime operations on namespaces like require (in the case of that blog post) or import (in your case)

qqq19:12:33

@tbaldridge: iirc, in one of your odin videos, you take an XML tree, flatten it into eav triples, and use a mini-logic language to query over it this seems to be like "collection oriented programming", in the spirit of SQL/APL do you know of other examples / tutorials of doing "collection oriented programming" ? (it s'like mapfilter/..., but more 'structured')

tbaldridge19:12:03

@qqq there's some stuff like that in core.logic.

tbaldridge19:12:13

And it's all fairly close to XSLT

qqq19:12:52

@tbaldridge: 1. is https://en.wikipedia.org/wiki/XSLT XSLT ? (I'm not drawing the connection, and not familiar with XSLT) 2. I've been looking at APL + SQL a lot lately, and it seems possible to write general purpose (for some def) programs in those languages, and they have this notion of "everything is a tensor . everything is a table of rows" that is a bit stronger than clojure collections, but I can't quite understand it

chris19:12:00

seems like everyone gave up on xslt which is too bad

chris19:12:04

xslt is great

tbaldridge19:12:41

@qqq yeah, XSLT is a query/transformation language for XML written in XML ( 😐 )

chris19:12:18

the syntax is mindboggling, but you can do some very complex translations in an incredibly simple way

chris19:12:40

unfortunately, pretty much everyone left it behind 10 or 15 years ago

qqq19:12:45

that's not too bad right? xml is basically (foo ...) -> <foo> ... </foo>

tbaldridge19:12:52

Exactly, convert all the XML to EDN and it wouldn't be half bad.

tbaldridge19:12:35

So those are the big "query arbitrary nested data" techs I'm aware of.

tbaldridge19:12:06

There's also JQuery and libs like Specter, but they differ a little in their lack of joins and multiple data sources.

qqq19:12:10

I'm interested in using APL / SQL for things beyond 'querying databases', and then porting the style to Clojure. For example, things like dijkstras algorithm / topological sort can get implemented in a particular way in APL, as well as game of life.

qqq19:12:28

And translating that over would get clojure code very different in style from 'common/idiomtic clojure style'

mikerod19:12:10

> Exactly, convert all the XML to EDN and it wouldn’t be half bad. Sort of funny in the use of the word “half” here

mikerod19:12:20

It’d be about half

mikerod19:12:46

(well better really, but close enough 😛 )

tbaldridge19:12:46

funny enough though, whenever I work with XML I really want something like XSLT in Clojure. Especially something where I can feed it 20 queries and an optimizer will compile it all down to a single fast gather function

mikerod19:12:47

sounds like a TODO for someone

flowthing20:12:25

Well, this might be too literal of an interpretation of "XSLT in Clojure", but https://github.com/eerohele/sigel 😛

flowthing20:12:44

>xslt is great Must be the first time I've ever heard anyone say that. Not quite everyone left it behind, though — it's still quite heavily used in the wonderful world of technical documentation and publishing.

jgh20:12:56

love the headshot that goes with it

flowthing20:12:25

It's pretty obnoxious to see your own face like that, I always forget that happens when you paste a GitHub link here… sorry about that.

jgh20:12:50

haha well it’s github’s fault really

jgh20:12:53

> xslt is great I feel like this might have been more common to hear pre-json.

jgh20:12:26

i seem to remember finding it to be neat back in college, but we’re talking early->mid 2000's.

zalky20:12:52

Hi all: I'm working on a boot based web-app. The environment is set up in a way that allows me to develop and deploy it directly, but I would also like to be able to use it as a basis for derived apps that would extend the core tech. It seems there would be two approaches to this: 1) fork the repo, and use standard distributed git workflows to merge features between the core and derived apps 2) package the core app as a library to be consumed by other projects The first would seem to make it pretty trivial to merge features back and forth between the different forks, but would eliminate the distinction between upstream and downstream. The second would maintain a very clear distinction about where features are coming from to make a coherent system, but makes integrated development a little more cumbersome. I'm wondering if folks have had experience with deriving one app from another, and what approach they used to do integrated development (either the first or second approach above, or some third approach).

jgh20:12:49

could use git submodules instead of forking

jgh20:12:01

not everyone likes them though, but it’s a matter of taste

flowthing20:12:12

@jgh: Just curious, did the headshot disappear for you? Wondering whether what I did to remove it works for just me or everyone…

New To Clojure21:12:36

@U4ZDX466T How did you removed that picture? Wherever I paste Github link it always looks like that.

flowthing06:12:34

If you hover over the area where the picture is, an X icon appears to the left of the gray border. Click there and Slack asks you whether you want to remove the attachment.

jgh20:12:35

yeah looks like whatever you did removed your profile image

jgh20:12:58

@zalky for #2 i think the question becomes how often are the sdk and clients developed in tandem? If the workflow is very often going to be the client dev is also working on the core sdk to create their features then perhaps doing a lib distribution is not the most efficient way of doing it..at least at the beginning. If your core sdk doesnt change much and may occasionally need updates maybe the extra overhead is something you can live with. Maybe it’ll also encourage more thoughtful api design since it’ll be a pain to work on the core sdk 😉

zalky21:12:19

@jgh: thanks for the submodules rec, I haven't used them in a while, so I will have to do a bit more reading. In another channel, someone recommended the use of "checkout" dependencies, which I had not heard of, but also looks like an interesting alternative.

jgh21:12:58

ah yeah i guess that’s a boot-specific thing

Bravi21:12:08

how can I format

0.0115
to be
0.01150000
? I was trying like this:
(format "%.8f" 0.0115)

Bravi21:12:21

but throws an error all the time

Bravi21:12:53

hmm it seems to be working in repl 😕

dominicm22:12:24

@tbaldridge you seem to give a lot of value to logic programming. But I don't ever seem to find a practical use for it in my work, so I presume I'm missing something. Any hints?

tbaldridge15:12:37

Logic programming is a tool I use in what I call "code compression". As time goes on and a codebase grows I tend to see high level patterns that I would like to compress. For example, I may have a large XML structure that I'm parsing and I'm using tons of get-ins, reducing over the results and emitting them into some other format.

tbaldridge15:12:39

So at a basic level what I try to find are "code compression" algorithms that allow me to express the "what" without the "how". Often this goes beyond stuff like get-in or specter as I also need aggregation, advanced predicates, etc.

tbaldridge15:12:46

Most of the time what I end up using is an ad-hoc engine that does just enough to fulfill the needs of a given client, but I'd love to see something more advanced.

tbaldridge15:12:43

Once you have a DSL of sorts that expresses declaratively what you want to do, the next question is "how do I optimize the output of this engine". This also then allows me to separate the "what" from the "how to do it fast".

tbaldridge15:12:37

Instaparse follows this, you express the "how" in the EBNF language, and then the parser engine figures out how to make it fast. If in the future Instaparse figures out how to optimize some construct, I don't have to change my code, I just pull down their new lib.

tbaldridge15:12:11

The same thing could be done in a very simple way with something like get-in. Perhaps get-in could take many paths and then find common sub-paths in the arguments only traversing into children once per unique subpath.

dominicm22:12:31

I would presume this kind of thing can only come in later in a project then, after the patterns have emerged. That would explain why our experiences differ. I've spent more time in the greenfield part of a project, and very little time in the stage where you're extending existing code. We have a few places where we achieve something of a similar goal with data, e.g. defining schemas related to a graphql request, and allowing a small bit of code extract that. I think the scariest part of what you said was "[building] an ad-hoc engine", I don't even know where I'd start really. Reading through odin, I find terms like "unification" and "tabling" quite intimidating. I should perhaps purchase your series where you build odin to try and learn more about Karen and such.

dominicm22:12:15

Fwiw, I really like Odin so far. I'm trying to use it for querying REST apis. I've had to put a memoize in though (I want to replace this with a ctx cache), as Odin was "forking" (my term for the separate paths after doing an additional query) queries when I didn't expect it to, as there was no overlap in the inputs. I'm not sure if I'm using it properly, or even if I'm benefiting from it. I initially reached for datalog/datascript to do this, but being unable to make arbitrary rest queries made it difficult (having to commit to a db after doing part of the query I'm interested in probably doesn't give me much benefit.

dominicm22:12:44

I'm struggling now with something in odin, which is something to the effect of: - I've fetched all members from API - I've fetched all tasks from API - I want to find the assignee of a task - I want to find the owners of a task I seem to keep filtering all the members, instead of creating a list of members named "assignee". The closest way I came to achieving my goal was (o/and (= (:assignee_id ?task) (:id ?member)), which obviously doesn't involve any bindings. I wondered if I'd need to use o/== but I wasn't certain how I'd do that.

dominicm23:12:46

Maybe I should be "re-fetching" a list of members for assignees.