Fork me on GitHub
#beginners
<
2019-01-15
>
Daouda01:01:57

hey guys, can you tell me what i am doing wring here (swap! profiles apply assoc [id1 profile1 id2 profile2]))? is it possible to do that?

ghadi01:01:49

@quieterkali assoc is variadic, so you can do: (swap! profiles assoc id1 profile1 id2 profile2))

ghadi01:01:23

swap! and most core functions that resemble it (update-in, update, etc.) expand out to put the thing you’re swapping in between the function and the args

ghadi01:01:16

your swap! call used #(apply % assoc [id1 profile1 id2 profile2]) but the argument should have been #(apply assoc % [id1 profile1 id2 profile2])

ghadi01:01:26

which swap can’t make happen for you

ghadi01:01:19

unless you call swap like so: (swap! profiles #(apply assoc % [id1 profile1 id2 profile2])) which is clumsy

Daouda01:01:54

i am going to use apply on the outer function then

ghadi01:01:36

which outer function?

Daouda01:01:45

the one who call the function with the piece of code i pasted here

hiredman01:01:51

swap! internally calls apply

hiredman01:01:19

the problem with your call is the argument order

Daouda01:01:30

so i can just pass an array to it like argument?

hiredman01:01:14

(swap! profiles apply assoc [id1 profile1 id2 profile2])) results in a function call like (apply @profiles assoc [id1 profile1 id2 profile2])) which is of course, incorrect

hiredman01:01:38

no, because swap! uses apply on the varargs

hiredman01:01:15

you of course want (apply assoc @profiles [id1 profile1 id2 profile2]))

noisesmith01:01:37

you can use (apply swap! ..) though

Daouda01:01:16

outer function: (save [id profile] (save-profile! id profile ))

Daouda01:01:59

(save-profile! [id profile] (swap! profiles assoc [id profile])

Daouda01:01:21

this work file for id profile

Daouda01:01:29

one id and one profile

hiredman01:01:44

do you understand why (swap! profiles apply assoc [id1 profile1 id2 profile2])) doesn't work?

Daouda01:01:54

i want to make it receive an array of ids and profiles and swap them

hiredman01:01:29

swap! takes an atom, and a function, and some arguments, then atomically sets the value of the atom to (apply fun value-of-atom args)

hiredman01:01:49

in your call, you are passing in apply as the function

😱 5
hiredman01:01:05

assoc, and the vector are then treated as arguments

😱 5
Daouda01:01:26

now i understand why it won't work. Thank you very much for your explanation 🙂

Daouda01:01:06

so using another apply make no sense

hiredman01:01:19

actually it would work

hiredman01:01:33

or not another apply

hiredman01:01:39

but moving the apply

hiredman01:01:02

or turning apply+assoc into a function

noisesmith01:01:23

(apply swap! profiles assoc id-list) will work, as would (swap! profiles (partial apply assoc) id-list)

noisesmith01:01:57

or the #() constructions suggested above

Daouda01:01:10

any way to make it work without using apply?

noisesmith01:01:34

the lambda that ghadi suggested

hiredman01:01:13

I would question the format of the arguments

hiredman01:01:45

like why is it getting passed a vector of [id profile id profile] and not a map of {id profile} or a vector of pairs [[id profile]]

hiredman01:01:11

(swap! profiles merge profile-map)

hiredman01:01:25

or (swap! profiles into vector-of-profile-pairs)

Daouda01:01:35

thank you all for the help 🙂

macrobartfast02:01:27

when opening a project with cider and emacs, I often want to interactively work on functions... if dependencies/imports of my own code are in other files, I have to open all of those buffers and evaluate everything in them to avoid errors...

macrobartfast02:01:37

is there a way to evaluate everything? on a related note, can anyone explain to me what's going on here? when I run a project from the repl, it seems like everything is being evaled on launch... why/how is this different from opening a project and using cider to eval things?

noisesmith17:01:33

> when I run a project from the repl, it seems like everything is being evaled on launch this isn't a built in clojure behavior, it's being done by a project-manager (eg. lein) config

noisesmith17:01:54

you can do the same thing via (doto 'my.ns require in-ns)

noisesmith17:01:11

(in a regular repl, I'd assume CIDER would accept this as well)

noisesmith17:01:54

I'm sure there are good shortcuts for CIDER, probably more appropriate to ask in the #cider channel if you need more info specific to that tool

macrobartfast02:01:20

I use cider to connect to a running repl, btw.

Acted07:01:29

Hello everyone: I would like to have a tread that updates a graph of incoming data over a web socket. Are there any good dynamic graphing libraries in Clojure that I can’t seem to find with google?

lemons10:01:11

Hey. I was wondering if I'm doing something wrong with clojure.test or it's error reporting is a bit ... weird. I have some test code:

(defn assert-pieces [game expected-pieces-repr]
  (let [select-for-comparison (fn [piece] (dissoc piece :id)) ;; generating pieces creates unique ids
        actual (->> game :pieces (vals) (map select-for-comparison))
        expected (->> expected-pieces-repr (parser/parse-pieces) (vals) (map select-for-comparison))]
    (is (= expected actual))))
When I break a test I get this:
expected: (= expected actual)

  actual: (not          
           (=
            ({:size 1, :owner "p1", :location {:x 0, :y 0}, :orientation :up}
             {:size 1, :owner "p1", :location {:x 1, :y 0}, :orientation :west})
            ()))
This seems really hard to parse. I'd expect expected value to have been evaluated and printed out, but instead I get the original expression. Actual section has both actual and expected variables eval'd but it's still pretty hard to understand which is which without going back to read your assertions.

pavlosmelissinos11:01:53

actual shows expected and actual in the order you use them in the test, so

expected: (= gt result)

actual: (not
         (=
          gt
          result)
In your case, it expected:
({:size 1, :owner "p1", :location {:x 0, :y 0}, :orientation :up}
             {:size 1, :owner "p1", :location {:x 1, :y 0}, :orientation :west})
but got () Seems pretty straightforward to me 😉 EDIT: renamed actual/expected to result/gt in order to avoid confusion

lemons11:01:01

I guess im just used to junit/scalatest where i'd get

expected: ({:size 1, :owner "p1", :location {:x 0, :y 0}, :orientation :up}
             {:size 1, :owner "p1", :location {:x 1, :y 0}, :orientation :west})
actual: ()

pavlosmelissinos11:01:02

I think the difference is clojure assertions don't always check for equality

pavlosmelissinos11:01:27

So you don't necessarily have two expressions that should match. is only checks whether a single expression is true. What that expression is comprised of is up to you

pavlosmelissinos11:01:06

Does that make sense?

lemons11:01:14

Yeah. I think i'll get used to it soon

🙂 5
dangercoder13:01:43

I have a instant time like this

#inst "2018-10-14T13:21:56.000-00:00" 
whats the easiest way to get the hours,minutes and seconds like: "13:21:26"?

dangercoder13:01:57

i guess I can use clj-time here?

temco13:01:00

it could be solved by (->> inst .toString (re-find #"\d{2}:\d{2}:\d{2}"))

dangercoder13:01:26

worked perfectly thank you 🙂

dangercoder13:01:38

now i just need to regexp for the date 2018-10-14 but i'll manage. thanks again!

dangercoder15:01:34

seems like it casts the time to my time.

dangercoder15:01:41

converts it from utc to gmt+1

dangercoder14:01:49

is it possible to grep a file from the shell in clj and get the result as text?

manutter5114:01:38

Sounds like something planck or lumo would be good for.

dazld14:01:12

maybe a silly question, but how would I get to a var (if it exists) from an arbitrary value..? eg, from a passed function

dazld14:01:44

var is a special form, so I can’t invoke it like a function to get the var, right?

dazld14:01:54

ie, this doesn’t work:

(defn get-query [f]
 (some-> f
         var
         meta
         :query))

smnplk14:01:37

if you use -> it should work. some-> doesn't work because it does some nil checking under the hood

dazld14:01:16

that helped, thank you

smnplk14:01:04

@dazld try running (resolve (quote f))

smnplk14:01:12

instead of var

dazld14:01:56

think i’m still missing something

dazld14:01:03

say, you have a collection of functions

dazld14:01:09

and each function has meta data

dazld14:01:27

what would the function to extract that meta data from the collection of functions look like?

dazld14:01:32

the functions aren’t quoted

smnplk14:01:34

(some-> f quote resolve meta :query) something like that

bronsa15:01:09

quote like that makes no sense

bronsa15:01:50

you're writing (resolve 'f)

dazld15:01:54

(def example [+ / *])
=> #'__/example
(map meta example)
=> (nil nil nil)

bronsa15:01:20

@dazld metadata is on vars not on the objects

bronsa15:01:29

try (map (comp meta resolve) example)

bronsa15:01:44

with

(def example `[+ / *])

bronsa15:01:53

(note, symbols, not resolved objects)

dazld15:01:15

i think this is the fundamental thing I’m having a brainfart with

bronsa15:01:25

symbols resolve to vars

bronsa15:01:28

vars deref to values

bronsa15:01:49

when you write + you're getting the dereffed value of the var clojure.core/+

bronsa15:01:00

if you want the var, you write (var +) or #'+

bronsa15:01:16

if you want to dinamically retrieve a var from a symbol, you use resolve on the symbol

bronsa15:01:23

so (resolve '+)

dazld15:01:23

but you can’t do that programmatically, if you don’t have the symbol

dazld15:01:42

okie, that clears it up

bronsa15:01:15

you can't map back a value to its original var

bronsa15:01:38

the mapping can't exist (unless you annotate the value with the original var, using metadata)

smnplk15:01:08

@bronsa that is exactly what i did

smnplk15:01:35

i called resolve on a symbol

bronsa15:01:45

you called resolve on 'f

dazld15:01:52

I wasn’t passing a symbol though, that was the issue

bronsa15:01:16

which is the same as writing #'f

bronsa15:01:32

and makes very little sense, it's a constant

smnplk15:01:57

(def f [] "blala") (some-> f quote resolve meta :query) that is the code i tried in my repl

bronsa15:01:40

ah :) ok sorry, I thought you were proposing that as a body to his get-query

bronsa15:01:48

as a standalone example it makes sense yeah

👍 5
dazld15:01:03

the programmatic thing was what i was after

dazld15:01:16

when you run this stuff directly on a repl, it all ties together fine

dazld15:01:28

thank you both btw, that was helpful

dazld15:01:39

I thought there may be some magic way to get back to the var from a value

dazld15:01:46

(without gymnastics)

smnplk15:01:55

@dazld Oh i see.. you are doing some black magic stuff. I am not experienced enough.

dazld15:01:05

I don’t think it’s black magic..

dazld15:01:17

wanted to annotate a function withe metadata

dazld15:01:25

which seemed reasonable enough 😉

bronsa15:01:03

you're trying to do compile-time things at runtime

dazld15:01:34

not intentionally! 😄

dazld15:01:55

was interesting knowing how the value resolution works though

dazld15:01:22

((resolve '+) 1 2) gives 3 too

Iwansyah Putra15:01:28

How much differences does Luminus and Re-frame? Do I need to learn Reframe to start learning Luminus?

manutter5115:01:04

Luminus helps you build pre-configured web applications, optionally including re-frame as a front-end component. You can start learning luminus before you start learning re-frame.

Iwansyah Putra15:01:33

So, is ti possible and recommended if I build Rest API server with Luminus and building Rest API with Re-frame, in a single project?

manutter5115:01:02

Well, let me re-phrase that slightly just to make sure we both have the same understanding: You can use luminus to build a server-side REST API, and you can use re-frame to build a client-side user interface that communicates with the server-side REST API. Yes, you can do both in the same project.

Iwansyah Putra15:01:51

Oh ya ya.. I got it. Thank you @manutter51

Chase18:01:47

I was just curious about a namespace issue. if I'm in my clojure-noob.core file and have a repl connected, if I change my ns from user to (ns clojure-noob) then I seem to lose the ability to look up simple docs like (doc inc) or whatever. Do most people stay in the user ns?

Chase18:01:33

and if I'm still in the user namespace but I load my buffer (in Cider) using C-c C-k then I still don't seem to have access to my created functions in the user namespace. I do have access to them if I manually send them to the repl like C-c M-p

noisesmith18:01:43

that's because in-ns doesn't initialize your ns or load the requisite code

noisesmith18:01:02

require or otherwise load the namespace from the file before switching to it

noisesmith18:01:43

if you are creating an ns from scratch, use ns instead of in-ns

noisesmith18:01:27

loading a namespace doesn't make its vars available in your current ns - you can use require with :as to access the ns via a shorthand, or switch to that ns after loading it

Chase18:01:41

ok. thank you. and am I able to get access to look up docs from my clojure-noob ns?

noisesmith18:01:17

if you mean the doc function, you can run (use 'clojure.repl) from the repl to access it again

noisesmith18:01:45

your default repl starts with clojure.repl in scope via use, it also has clojure.pprint/pprint mapped to pprint

noisesmith18:01:06

you need to set this up by hand in other namespaces if you need it

noisesmith18:01:41

also, if you use in-ns without creating the ns first, and everything seems broken, you can use (clojure.core/refer-clojure) to get the default clojure.core functions back

Chase18:01:29

perfect. thank you!

noisesmith18:01:30

I find that some experimentation with these functions in the repl should clear up how things work relatively quickly - after that you can also use the convenient shorthands that your editor provides and you'll actually understand what went wrong if one of the steps goes wrong

enforser19:01:21

Does anyone know of a library which converts from EDN to JSON that won't hit a StackOverflowError with a deeply nested map? I've tried Cheshire and clojure.data.json but neither seem to support this. I suppose I'm looking for something which is tail recursive

noisesmith19:01:35

Tail recursion for tree operations is tricky (you end up having to move work that was implicitly being done by stack operations into explicit data management in the heap), so I'm not surprised the standard libs don't implement this.

dpsutton19:01:44

do you know how deep it goes? I know update-in is recursive but not tail recursive. Be interesting if you can't update in it either

enforser19:01:34

I think I may have just figured out that I don't need actually need that functionality anymore

enforser19:01:29

I'm passing the response of a query to datomic to the json generator, and didn't consider that it may be evaluating a lot of nested relationships which I don't actually want - which is why the map is deeply nested

noisesmith19:01:04

a gordian knot solution could build an adjacency list (effectively flattening a tree in a way that keeps all info needed to reconstruct the tree), and then do the reverse operation on the consuming side

noisesmith19:01:13

but yeah, better yet just don't encode some data

noisesmith19:01:05

eg. I wouldn't be surprised if datomic is able to feed you cyclic data, so eagerly consuming it would always blow up

uwo19:01:24

Has anyone heard thru the grapevine whether the Elements of Clojure will have a print run?

dpsutton19:01:52

there's for sure been discussions. best way to find out is to tweet at @ztellman

🙏 5