Fork me on GitHub
#clojure
<
2017-07-18
>
qqq02:07:08

keep, for, map -- they want pure functions and return a lazy list

qqq02:07:18

I want something which is okay to pass an unpure function to ... and returns a strict list

qqq03:07:42

in good clojure style, do people do (map impure-function ...) or do we do something else when we have to run an impure function and also get its return value ?

danielcompton03:07:04

@qqq usually you'll use doall

danielcompton03:07:48

if you care about the return value

joshjones03:07:50

@qqq it is fine, as far as I know, to pass a function with side-effects to keep, filter, etc -- the gotcha is that you should not expect that your code will necessarily execute. So, your side effect may happen, and if you don't mind, great -- but, your side effect might not happen, and that's why it says to avoid impure functions (or in some cases, may get called more than once).

noisesmith03:07:57

it also might happen 31 times more than you expected

joshjones03:07:08

@qqq not sure why you want a "strict list", but for eager evaluation with guaranteed "run-once", reduce would be a decent candidate to build it:

(defn eager-map [f coll]
  (reverse (reduce #(conj % (f %2)) () coll)))

donyorm03:07:09

Does anyone know how to specify a stylesheet for a scene in fn-fx (a clojure wrapper for JavaFx)? https://github.com/halgari/fn-fx

baptiste-from-paris20:07:40

have you found your answers ?

donyorm05:07:24

Not yet. Posted an issue on the github but no answers.

qqq03:07:26

@danielcompton , @joshjones : okay, so despite the docs saying "use pure function", it's actually okay to assume atmost once, in order semantics -- i.e. we don't know how far it will exec (due to evaling thunks at a time) -- but we can assume that: 1. thunks, if evaluated, at evaluated at most once 2. thunks, if evaluated, as "in order" so (head (map f '(1 2 3 4 5))) won't do (f 1) (f 3) eh, let's skip 3 & 4 ... and then just eval (f 5) just for kicks

joshjones04:07:05

@qqq in the case of the current implementation of map, I'd say so -- with the obvious disclaimer that making assumptions like this and relying on these details is not safe, and that I wouldn't use an approach like this (I'd prefer the eager-map function I put above, for example) in the case of something like a comparator, it's quite likely that it will be executed more than once, per pair, so you would definitely not get any guarantees there.

tjscollins04:07:26

I'm getting a bizarre repl error that occurs only when reloading a file:

2. Unhandled clojure.lang.Compiler$CompilerException
   Error compiling *cider-repl webtools* at (1:1)

1. Caused by java.lang.RuntimeException
   No such var: user/reset
The project compiles fine. The repl starts fine. The problem only happens if I use C-c C-x to recompile. If I restart the whole repl, it compiles fine. It seems like it's trying to compile the repl buffer, but I can't for the life of me fathom WHY. Wondering if anyone has any ideas what would cause this. The only hit on stack overflow suggests that I must be requiring something :as user, but I'm definitely not.

tjscollins04:07:18

Tried a lein clean but that didn't make any difference.

qqq04:07:33

@joshjones : thanks for the eager map; it seems surprising that 1. core has no eager-map 2. many are probaly using (doall (map ...)) to simulate it, but 3. this revolves around assumptions that map doesn't really guarantee

qqq04:07:26

@tjscollins : what is user/reset ? is it part your lein config, part of cider, part of some reload package that you are using? [I use boot]

tjscollins04:07:06

@qqq User is the init-ns for a repl in my project.clj (lein config).

tjscollins04:07:48

@qqq so It seems that it expects a symbol user/reset that suddenly doesn't exist. But looking over my changes from the past day I don't see anything that I would expect to affect that.

tjscollins04:07:39

@qqq Well, restarting emacs finally seems to have fixed it.

qqq04:07:25

yeah, emacs can be quirky like that

rdivyanshu08:07:00

How to avoid reflection warning in gen-class state. Specifically I looking for answer for this question https://stackoverflow.com/questions/6625104/adding-a-type-hint-to-a-clojure-gen-class-state-access

vadyalex11:07:11

Hello fellow clojurians. I am eager to refactor part of my function that use destructuring but having some problem. Here is a code snippet that has sequence of files that are grouped based on hash, uploaded and flattened back.

(->>        
      items
      (group-by :hash)
      (pmap #(let
               [[hash [{file :file}] :as group] %]
               (if (upload hash file)
                 (second group))))
      (flatten))))
Is there a better way to destructure group into key and values to avoid performing (second group)?

vadyalex11:07:42

Ok, so the only thing I came up with is:

(->>        
      items
      (group-by :hash)
      (pmap #(let
               [[hash values] %
                 [{file :file}] values]
               (if (upload hash file)
                 values)))
      (flatten))))
Is it any good?

jahson12:07:05

values is a vector

vadyalex12:07:46

@andre.stylianos, @jahson is correct - values is vector. It may work if we update it:

(->>        
      items
      (group-by :hash)
      (pmap (fn [[hash values]]
			(when (upload hash (:file (first values)))
                  values)))
      flatten)))

andre.stylianos12:07:20

Oops, my bad. Missed that

andre.stylianos12:07:50

That should work

jahson12:07:28

Though I don’t know if there is any point to removal of (second group)

jahson12:07:08

You may as well do this [[hash [{file :file} second] :as group] %]

vadyalex12:07:57

@jahson Correct. That is my initial version. But don’t you think destructured version is more readable?

jahson12:07:39

@vadyalex Nope, imo — you need to parse destructuring and for that structure it is not very easy.

roklenarcic13:07:54

when using datomic, if I can freely choose between an SQL backed datomic or Cassandra backed datomic, which one is better?

mrchance14:07:21

@tkircsi It's because of the way transducers work. They are applied from right to left, but to the reducer fn.

mrchance14:07:33

You can think of each wrapping the earlier transducers

zylox14:07:43

@tkircsi https://clojure.org/reference/transducers checkout "defining Transformations with transducers"

michaellindon14:07:58

I'm trying to do some Java interop using a Java library called Gurobi. I'm following their documentation which reads

import gurobi.*;
...creates outer class...
GRBEnv env = new GRBEnv("mip1.log");
GRBModel model = new GRBModel(env);
GRBVar x = model.addVar(0.0, 1.0, 0.0, GRB.BINARY, "x");
I am trying to work with this library in clojure. It seems I cannot wildcard import in clojure so I have
(import '(gurobi GRB GRBCObj GRBCallback GRBColumn GRBConstr GRBEnv GRBExpr GRBException GRBGenConstr GRBLinExpr GRBQuadExpr GRBModel GRBSOS GRBVar GRBQConstr GurobiJni))
(def env (new GRBEnv "mip1.log"))
(def model (new GRBModel env))
(.addVar model 0 1 0 GRB.BINARY "x")
however I get the error on the final line "java.lang.ClassNotFoundException" caused by GRB.BINARY. I believe I have imported everything using the extensive import above.

mrchance14:07:28

@michaellindon Might be a static member, so it could be GRB/BINARY

mrchance14:07:51

Or, an inner class, in which case you need to import GRB$BINARY, but from the upper case spelling, I'd assume the former

michaellindon15:07:14

How would I convert x.get(GRB.DoubleAttr.X) to clojure

michaellindon15:07:19

cider in emacs isnt giving me much help ><

michaellindon15:07:48

so this worked (.get x gurobi.GRB$DoubleAttr/X) but i feel like im in the dark

michaellindon15:07:04

cider isn't giving me any autocompletion help so its hard to find the proper structure

michaellindon15:07:21

cidre doesn't autocomplete gurobi.GRB$... at all

tkircsi14:07:00

@mrchance @zylox Thx. I’ll check it again.

michaellindon14:07:14

it was GRB/BINARY, thank you

michaellindon15:07:29

can someone please help me convert x.get(GRB.DoubleAttr.X) to clojure code

michaellindon15:07:06

so turned out I needed this

michaellindon15:07:08

(.get x gurobi.GRB$DoubleAttr/X) But I'm confused as to why I needed gurobi.GRB$DoubleAttr instead of GRB$DoubleAttr as I already imported gurobi.GRB in my import statement

michaellindon15:07:47

and when I begin to type gurobi.GRB$Dou.... cider doesn't autocomplete it

mrchance15:07:15

@michaellindon Yeah, nested classes are confusing to work with... You can probably directly import GRB$DoubleAttr as well, that should fix it

noisesmith16:07:34

@qqq @joshjones clojure has eager-map built in, it’s called mapv, and it will perform better than that reduce example, even if you need to call seq on the result to get a list instead of vector

ag16:07:08

what's the best and most elegant way when using environ/env to ensure that values that can be coerced end up being so. Right now everything it reads as strings. I'd like values like "true"/"false" and numbers to be converted to be of the right type

ag16:07:02

Tried simply using edn/read-string, but it turned out to be not so straightforward.

ag17:07:04

some edge-cases when the exceptions thrown, I end up with code that doesn't look elegant. Clojure has spoiled me: If code doesn't look elegant - I feel it's not worth adding it.

noisesmith17:07:28

I wonder if plumatic/schema coercers would help here…

noisesmith17:07:26

> Coercion is like validation, except a schema-dependent transformation can be applied to the input data before validation.

noisesmith17:07:34

@ag consider that you’ll read this at startup, and IMHO startup is the perfect time in the run of an app to reject input outright and exit with an error

noisesmith17:07:29

so I’d say, don’t try/catch, even explicitly throw AssertionErrors if the data isn’t “perfect” - then whoever set up the run environment can use your clear descriptive error message to fix the input and try again

ag17:07:25

@noisesmith I'm not using schema in this particular project. Seems to be an overkill to have to use it to solve this particular problem

noisesmith17:07:46

OK - but my point about asserting / throwing / bailing out still stands

lwhorton18:07:43

is there a way to change the signature of a defmulti after you decide on which arguments to dispatch?

(defmulti foo (fn [a b] [a b]))
(defmethod foo [:foo :bar] [just-foo?] (do ...))
or does every defmethod have to have the signature [a b]?

hiredman18:07:39

the defmethod only needs to be able to be invoked on the args given to it

hiredman18:07:27

so if you have a mutlimethod that can be invoked with differing numbers of arguments, and those differing numbers of arguments are dispatched differently, each method only needs to handle the arity it would be invoked with

hiredman18:07:42

if you invoke a multimethod with N arguments, whichever method it dispatches to will be invoked with N arguments, you can't change that

lwhorton18:07:18

okay, that makes sense. I just didnt want to have to change my signature across a couple files that implement the defmethod *if at all possible

bja18:07:22

@ag @noisesmith I did exactly that using the json coercer that ships with schema

noisesmith18:07:37

yeah- that’s what I was thinking of

bja18:07:29

I have a file in each of my projects that looks like

(def settings {:debug {:schema s/Bool :default false}
   :db-uri {:schema sc/URI :default ""}
   :redis-uri {:schema sc/URI :default ""}})

bja18:07:19

and then I have a component that takes a settings map in and can realize those at component/start time to be injected around to whomever needs them

bja18:07:05

although I have a vendoring of environ.core/env's underlying functions to allow me to invoke it in my start() and thus allow me to stop a system, change java properties, and then start the system again

plins18:07:05

hello everyone, i have a giant regexp, is it possible to break it into various lines? or build it from a string (which can be broken into various lines and assembled together with str)

ghadi18:07:37

yes you can do that by calling (re-pattern (str the pieces of the regex)) or java.util.regex.Pattern/compile

plins18:07:49

thank you! the clojure docs are somewhat hard to navigate, sorry for the dumb question

qqq20:07:10

@noisesmith @joshjones : I'm an idiot for forgetting mapv; for some reason, I always thought "this was for ppl who wanted vector instead of list" but never eager vs lazy or impure vs pure

michaelblume20:07:16

So I’m looking at the honeysql README

michaelblume20:07:23

and it has loads of example code

michaelblume20:07:25

which is great

michaelblume20:07:30

except sometimes it goes stale

michaelblume20:07:47

and someone messages us to tell us that one of the examples in the README doesn’t run anymore

michaelblume20:07:53

and I was thinking

michaelblume20:07:07

we could set up a test case that actually parses the README

michaelblume20:07:16

and finds the backtick-quoted sections and evals them

michaelblume20:07:34

finds the forms preceded by => and treats them as expected results

michaelblume20:07:53

I’m wondering if anyone’s done this before/if this is something that already exists off the shelf

michaelblume20:07:12

because if not I could imagine throwing together a sort of ‘literate testing’ library to do this and sharing that

bja21:07:55

it sounds like a combination of org-mode and pythons doctests

hiredman21:07:06

there is a lein plugin for it if I recall

bja21:07:53

as I understand it, the python community has largely shied away from doctests (although I don't particularly know the reason; it might be an implementation issue)

bja21:07:43

@michaelblume it should be straightfoward to go the route you proposed using an augmented codeblock transformer with markdown-clj to grab the code blocks. See https://github.com/yogthos/markdown-clj#customizing-the-parser

bja21:07:46

(just thinking about it from the perspective of reusing existing stuff to avoid writing markdown grammar or some regexes)

jcf22:07:49

@michaelblume Elixir has something like executable documentation that (I think) centers around iex.

nwjsmith22:07:33

Playing around with spec-ing clojure.core/sort and I came across something interesting:

(frequencies [Double/NaN Double/NaN])
=> {NaN 1, NaN 1}

nwjsmith22:07:02

ah, this is why

nwjsmith22:07:19

(= Double/NaN Double/NaN)
=> false

bfabry22:07:10

lol.... I guess that makes some math I don't understand work

seancorfield23:07:40

@michaelblume If you're willing to live with Midje, there's a plugin to run the readme code as a set of tests -- clj-time uses it.

michaelblume23:07:48

@seancorfield I’ve got clj-time checked out and I’m actually having a hard time figuring out how to see/run the readme tests

michaelblume23:07:02

docs say to run lein test-readme but I’m getting no such task

michaelblume23:07:17

and the test/readme.clj file that got generated looks really short

seancorfield23:07:14

lein with-profile dev,default,midje test readme -- only code annotated with clojure (not clj) is turned into Midje facts