Fork me on GitHub
#beginners
<
2019-03-01
>
johnj04:03:04

How should this -Dclojure.server.repl="{:port 5555 :accept clojure.core.server/repl}" look like when passed to :jvm-opts ?

johnj04:03:03

tried enclosing everything in double quotes and escaping the inner ones

Alex Miller (Clojure team)04:03:33

unfortunately there are some issues with handling this due to the various layers of spaces/escaping/quoting

Alex Miller (Clojure team)04:03:55

the trick is to replace the spaces with commas (as commas are whitespace to Clojure, but not to bash)

Alex Miller (Clojure team)04:03:37

so more like :jvm-opts ["-Dclojure.server.repl={:port,5555,:accept,clojure.core.server/repl}"] I believe

Alex Miller (Clojure team)04:03:01

eventually this will be fixed, but it's kind of a nightmare

johnj04:03:50

oh I see, yep that works, thanks

Alex Miller (Clojure team)04:03:30

sorry it's super weird :)

johnj04:03:28

quoting is one of bash most controversial things

Alex Miller (Clojure team)04:03:16

it's double weird because of how it goes from command-line, to Clojure, to a file, back to bash, and then into a java command line at the end :)

seancorfield05:03:26

@lockdown- If you're looking for "inspiration" with deps.edn, I'll point you to my .clojure file https://github.com/seancorfield/dot-clojure

seancorfield05:03:52

It has several comma-is-whitespace things in there 🙂

johnj05:03:42

@seancorfield handy, already seeing some needed stuff, thx

Saikyun13:03:36

is there a good online tutorial for beginners? want to recommend to some colleagues

borkdude14:03:05

There are a bunch of free ones. https://www.braveclojure.com is one that’s frequently mentioned

👍 5
Saikyun08:03:33

is it good?

3Jane15:03:18

I have a sequence of items. I’m mapping over them to transform them.

3Jane15:03:29

What’s the best option to generate a lookup table (hash map) from that?

bronsa15:03:18

what's the kv pairs in the table?

bronsa15:03:25

original item -> xformed item?

3Jane15:03:19

It starts off as a vector of things

3Jane15:03:37

Transformation function could return [key transformed-value] pairs

3Jane15:03:11

Sometimes it will return nil, for invalid input

3Jane15:03:47

I figured out a way to do it, but I’d like to know what a good way is to do it efficiently 🙂

3Jane15:03:05

ohh mapcat doesn’t mind a nil

3Jane15:03:53

in which case I can do (apply hash-map (mapcat transformation collection))

bronsa15:03:29

alternatively

bronsa15:03:30

user=> (into {} (keep (fn [x] (when (pos? x) [x (inc x)]))) [1 2 -2 3])
{1 2, 2 3, 3 4}

bronsa15:03:42

it's the best ever

3Jane15:03:01

is into faster than the above?

danielneal15:03:18

what does keep do?

bronsa15:03:32

map + filter identity

bronsa15:03:43

@lady3janepl the version with into + keep as transducer is both faster (into internally uses transients, and fast reductions of coll rather than converting to seq) and more efficient (doesn't allocate unnecessary objects)

bronsa15:03:13

hardly a massive performance gain but why not :)

3Jane15:03:31

thank you 🙂 I’m learning for the future

bronsa15:03:37

@danieleneal

clojure.core/keep
([f] [f coll])
  Returns a lazy sequence of the non-nil results of (f item). Note,
  this means false return values will be included.  f must be free of
  side-effects.  Returns a transducer when no collection is provided.

bronsa15:03:52

uh so it's filter some? not filter identity

bronsa15:03:54

forgot about that

3Jane15:03:44

what do you do when you have several things that can be nil

3Jane15:03:01

and the result is valid or not depending on their combination?

3Jane15:03:46

I’ve arrived at

(if (or t1 t2 t3)
      (when-some [keywords (get i "Keywords")]

bronsa15:03:47

not sure I follow

3Jane15:03:51

but that makes for slightly annoying nesting

3Jane15:03:23

in this case, I want to return a result if one of t1, t2 or t3, AND keywords, are not nil

danielneal15:03:30

you could use spectre perhaps

3Jane15:03:51

json juggling 😞

3Jane15:03:12

(I’m stripping an existing data file for my own purposes)

bronsa15:03:18

@lady3janepl how about lifting the the or into when-some

bronsa15:03:47

(if-some [keyword (and (or t1 t2 t3) (get i "Keywords"))] then.. else..)

bronsa15:03:07

your first version looks ok to me anyway

bronsa15:03:11

I'd probably prefer it

3Jane15:03:06

how about finding an element that matches a specific condition?

3Jane15:03:49

(I might just create another lookup map, but for the sake of example, if I was looking in a sequence of [ x1, x2, x3 … ] for the first element where (f x) returns true)

3Jane15:03:01

(first (drop-while #(not f))) or sth?

bronsa15:03:12

(first (filter

3Jane15:03:24

oh 😄 thanks

bronsa15:03:38

I've had (def ffilter (comp first filter)) in almost all my projects

victorb16:03:02

any way I can test the equality of anonymous functions without relying on the instance of the function itself?

victorb16:03:28

I have something like this:

(= {:name "simple-pipeline", :steps [{:name "log1", :func #object[ns.pipeline_test$first_func 0x8d8f754 "ns.pipeline_test$first_func@8d8f754"]} {:name "log2", :func #object[ns.pipeline_test$second_func 0x25673087 "ns.pipeline_test$second_func@25673087"]}]} {:name "simple-pipeline", :steps [{:name "log1", :func first-func} {:name "log2", :func second-func}]})))

dpsutton16:03:23

functions have reference equality. if they are anonymous they most likely won't be the same even if they are the "same"

victorb16:03:18

I see @dpsutton, even though I would do something like this?

(def first-func (fn [log] (log "Hello")))
(def second-func (fn [log] (log "World")))

(pipeline/defpipeline simple-pipeline
  "log1" first-func
  "log2" second-func)

(def simple-pipeline-output
  {:name "simple-pipeline"
   :steps [{:name "log1"
            :func first-func}
           {:name "log2"
            :func second-func}]})

victorb16:03:42

in fact, I think something is wrong with my macro I'm writing, as the first has :func #object[yadda.yadda] while the second has :func first-func

borkdude16:03:42

@victorbjelkholm429 yes, first-func and second-func are different objects.

borkdude16:03:56

they would be the same objects if you did (def second-func first-func)

dpsutton16:03:14

at which point you aren't testing much

borkdude16:03:31

you should never rely on “function equivalence”, it’s bad

victorb16:03:59

@borkdude no, that I understand. But I explicitly define first-func outside to be used in both. The function equality is something I'm only interested in the tests, not the in the running system

borkdude16:03:32

it will probably work because of reference equality then

victorb16:03:20

so, what I'm unsure about, is why one gets a reference while the other is just the symbols. Here is the full scope of what I'm doing https://gist.github.com/victorb/e7622a90db51abc19fe7f602ac6d4d4a

victorb16:03:53

most probably I'm screwing up something with the macro, as it's my second macro I try to write...

dpsutton16:03:49

which one is symbols?

borkdude16:03:05

you maybe want: ~(format-steps forms) instead of (format-steps '~forms)

victorb16:03:50

yup @borkdude, indeed what I want! Thanks

3Jane17:03:17

Is there a good way to map over a hash map, transforming values and preserving keys?

bronsa17:03:50

lots of utils libraries have a function called map-vals, it's not in clojure.core

3Jane17:03:27

thanks 🙂

bronsa17:03:42

or you can (into {} (map (fn [[k v]] [k (f v)])) {...}))

bronsa17:03:07

or the equivalent using reduce-kv

👍 5
Pavel Klavík17:03:33

hi, I am trying to get working server reloading with yada and mount whenever code changes. Not sure whether there is some yada specific solution, but as I understand mount (and similar libraries) should have support for this:

(defn create-server []
  (yada/listener
    ["/"
     [["" (yada/as-resource "Root")]
      ["hello" (yada/as-resource "Goodbye World!")]
      ["test" (yada/resource {:produces "text/plain"
                           :response "This is a test!"})]
      [true (yada/as-resource nil)]]]
    {:port port}))

(mount/defstate
            server
            :start (create-server)
            :stop ((:close server)))

borkdude17:03:59

I’m not sure why what wouldn’t work. Does it not?

Pavel Klavík17:03:00

maybe I am doing something wrong, here is the rest of the setup, based on Luminus template:

(defn stop-app []
  (doseq [component (:stopped (m/stop))]
    (log/info component "stopped"))
  (shutdown-agents))

(defn start-app [args]
  (doseq [component (-> args
                        (cli/parse-opts cli-options)
                        m/start-with-args
                        :started)]
    (log/info component "started"))
  (.addShutdownHook (Runtime/getRuntime) (Thread. stop-app)))


(defn -main [& args]
  (start-app args))

borkdude17:03:19

you’re not really asking a question

Pavel Klavík17:03:01

basically when I change create-server, I would like to have everything automatically reloaded

borkdude17:03:40

so you want to hook up mount/start and mount/start with a file system watching thing?

Pavel Klavík17:03:57

ya, I want whenever source code file is updated, we run mount/start (only on those which have :reloading turned on, so for instance not on db connection)

lilactown18:03:04

IIRC if you re-evaluate a defstate it will reload

Pavel Klavík18:03:45

and how do you hook it up to watching file system?

lilactown18:03:38

I normally don't watch the file system, I just re-evaluate the namespace

lilactown18:03:54

in my editor. I use Emacs or Cursive to integrate with my REPL

lilactown18:03:28

so I can just press a hotkey to send code to my REPL to be evaluated (like a whole namespace)

Pavel Klavík18:03:14

hmm, that would work

Pavel Klavík18:03:48

is it advantageous to not reload it automatically? I am quite used for the figwheel setup on the client, but not sure whether it works equally well on the server

lilactown18:03:11

I like both. in CLJS, hot reloading is easier because you often have to restart your whole system in order to see your changes

lilactown18:03:21

e.g. you need to re-start your browser application

lilactown18:03:42

when I'm doing work that doesn't need that entire-system-restart to get feedback, like working on some data transformations, business logic, etc., I like just sending stuff to my REPL

lilactown18:03:14

you can get the same general thing with either solution. I prefer the REPL more for the amount of control I get, e.g. I can just re-define one function or var, instead of the whole file

Pavel Klavík18:03:41

I see, is there some mount function to reload everything?

lilactown18:03:32

(mount/stop) and (mount/start)

Pavel Klavík18:03:18

But that will reload all resources, even those which with :on-reload :nope

lilactown18:03:51

you said you wanted to reload everything? or just some things?

Audrius18:03:09

what is this apostrophe means in here https://github.com/clojure/core.cache#example-usage after C1 (`C1'`) ?

lilactown18:03:26

if you re-define a defstate that is depended on by other defstates, it should reload all of the ones in the dependency chain

lilactown18:03:48

@masta in this case nothing. it's just part of the name

lilactown18:03:23

math people do that all the time. they'll have a variable called x, and then a variable that is derived from it will be x', x'', etc.

👍 5
Audrius18:03:26

oh it is just a valid symbol/char for a symbol

noisesmith18:03:57

@masta it's a naming convention, not a syntax, and it x' indicates "a slight variation on the thing with the name x"

noisesmith18:03:04

or "next version of x"

👍 4
noisesmith18:03:07

like in math

Pavel Klavík19:03:00

I see, thx lilactown for the info, I think I will start with what you suggest and maybe rework the setup later as I understand everything much better

lilactown19:03:43

is there a non-macro version of and?

lilactown19:03:40

I want to do something like

(-> validation-map
      (update :valid? and (apply-rule rule data)))

borkdude19:03:08

what’s in valid?

borkdude19:03:41

(update :valid? #(and % (apply-rule rule data)) ?

lilactown19:03:12

yeah I just like to avoid the nesting when I can 😛

borkdude19:03:36

there are variations of update around, like update-when in various libs

Daw-Ran Liou19:03:30

Do you usually clean up the var-quotes (`#'`) when releasing the software? I found var-quote a convenient way to try things quickly without reloading everything. For example:

(defn foo [name] (str "foo" name))
  (def bar-1 (partial foo "1"))
  (def bar-2 (partial #'foo "2"))
In this case, when I changed foo, I can evaluate foo itself and calling bar-2 would see the change. The only reason I'm using var-quotes is for development, so I'm wondering if it's a nice thing to clean them up afterwards.

borkdude19:03:53

I usually don’t

Daw-Ran Liou19:03:05

And a followup question is: what's the use cases for var-quotes other than development?

borkdude19:03:29

consider the use of a REPL into production: the line between dev and prod is blurred 😛

noisesmith19:03:51

the runtime overhead of using a var rather than a function in a first-class context isn't different from using something by name inside a normal function body, so you might find it ugly but it's not a behavior or performance problem

borkdude19:03:53

btw, if you don’t use partial then you usually don’t need the var indirection

10
Daw-Ran Liou19:03:33

Would you prefer writing a function like below instead?

(defn bar-1 [] (foo "1")) 

Daw-Ran Liou19:03:16

Or it doesn't matter

borkdude19:03:32

yeah, or if you need an anonymous one: #(foo "1")

Daw-Ran Liou19:03:34

Sorry I'm still trying to understand how to use the repl effectively

Daw-Ran Liou19:03:54

Yeah that looks nicer

Daw-Ran Liou19:03:20

Would you help me understand why (def bar-1 #(foo "1")) doesn't need to be re-evaluated with foo changes?

borkdude19:03:04

when you eval (foo 1) the function you want to invoke is obtained via the var #'foo

borkdude19:03:29

(unless you compile with direct linking, but this isn’t turned on by default)

borkdude19:03:40

but when you make a function (partial foo 1) then #'foo is only used once

Daw-Ran Liou19:03:23

Does all the #() forms invoke the symbols inside via their vars?

noisesmith19:03:32

@dawranliou the body of that function compiles to byte-code that looks up foo on each call

hiredman19:03:51

derefs foo on each call

borkdude19:03:10

all expressions do that, it doesn’t have to be within a function. e.g. when I eval foo in the REPL, the var is also “consulted”

borkdude19:03:58

the symbol foo is resolved to a var and then the value associated with that var is returned

noisesmith19:03:59

the distinction I was making was (fn [] (foo x)) and (partial foo x) - partial doesn't create bytecode that looks up foo, it gets passed only the value

noisesmith19:03:18

both create functions, only one is able to do that lookup

Daw-Ran Liou19:03:11

Thanks the conversation is very helpful. I had some misconception about vars and symbols.

5
seancorfield19:03:16

Note that you can pass a Var to partial:

user=> (defn foo [a b] (+ a b))
#'user/foo
user=> (def foo-2 (partial #'foo 2))
#'user/foo-2
user=> (foo-2 3)
5
user=> (defn foo [a b] (* a b))
#'user/foo
user=> (foo-2 3)
6
user=> 

👍 5
borkdude19:03:26

Note that is what the conversation started with 🙂

😂 4
seancorfield20:03:34

Hah! That'll teach me to scroll further back before diving in! 🙂

noisesmith19:03:40

same issue applies to fnil, comp, juxt, complement, etc.

Daw-Ran Liou20:03:55

I feel like @noisesmith’s list consists of many high-order functions. Does most high-order functions have this behavior?

noisesmith20:03:08

the ones that return a function

hiredman20:03:43

it isn't something a particular function does

noisesmith20:03:58

it's caused by the evaluation strategy of clojure - the symbol is resolved from a var to a value before being passed to the function, so it can't capture the var

hiredman20:03:00

it is required by the semantics of evaluation

noisesmith20:03:06

unless the var itself is explicitly what you pass

hiredman20:03:21

any function you pass an argument to, the argument is evaluated first

hiredman20:03:48

symbols are evaluated by looking up their value (either a local or derefing a var)

Daw-Ran Liou20:03:35

Am I understand it correctly: The symbols inside the fn form is only evaluated when the fn is called.

hiredman20:03:26

so the function partial, is passed the value that the symbol is resolved to, not the symbol

Daw-Ran Liou20:03:47

Phew that’s a big TIL for me

hiredman20:03:52

so when you change what that symbol would resolve to, too late the resolution has already happened

hiredman20:03:34

like if you had a mutable array A, set A[0] = 10, called a function with f(A[0]), and it returned R, and the changed A[0] = 50, R isn't going to change to reflect the change to A