Fork me on GitHub
#beginners
<
2017-05-09
>
crvst10:05:43

Hey, how to make one atom be dependent on another?

crvst10:05:28

Make (def atom-2 (r/atom (vec (map-indexed vector @atom-1))))dependent from (def atom-1 (r/atom some-data))

crvst10:05:29

I need to update some parent atom, but also need to notify derrived atom about updates

crvst10:05:12

How should I do this? Since dereffing with @ removes the link between structures

micahasmith11:05:52

@crvst its not with atoms, but is ensuring consistency via ref/`dosync` something that would work?

crvst11:05:06

Got it, thanks. I will look into this stuff.

Drew Verlee13:05:56

@crvst as michahasmith said, refs can ensure two updates across two states happen together (or both dont happen). If you just want to notify, then you can place a watcher on a state mechanism like an atom, which on change, will take some action.

noisesmith16:05:38

r/atom is cljs (reagent) there are no refs in cljs

grierson18:05:07

Does defmulit work off the order of the parameters? example (defmulti f [x] x) (defmethod f :inc [x y] y) (f :inc 10)

noisesmith18:05:20

@grierson the methods have to match the arity of the dispatch function

grierson18:05:31

I’m reading through https://github.com/roman01la/scrum and the defmulti function only takes one parameter but in some demethod take multiple.

noisesmith18:05:39

ugh - ok that works in cljs because cljs doesn’t have arity errors

noisesmith18:05:05

it’s not a correct usage though strictly speaking

noisesmith18:05:18

anyway, to your actual question, the dispatch is an arbitrary function that has access to all args to the method

grierson18:05:27

So it should be (defmulti [x & xs] x)

noisesmith18:05:32

dispatch is always based on the return value of the dispatch function

noisesmith18:05:44

@grierson yes, that would be correct

noisesmith18:05:06

and you could easily write a dispatch that only looks at the third arg

noisesmith18:05:16

or just generates a random number as the dispatch value, ignoring all args

noisesmith18:05:19

it’s just a function

grierson18:05:24

Ok, thanks. I was wondering how it was working in the examples on the project.

matan19:05:51

small question: is https://github.com/levand/immuconf or some other lib commonly used for configuration? or is there something in core language which is typically used for small-enough projects? for small projects I often just want to load a map from a file, so I am tempted not to use any library at all. Any idiomatic way other than just slurping the file?

dominicm19:05:12

matan: if you want a file, use edn

dominicm19:05:33

matan: if you need environment vars on top of that map, check out aero

matan19:05:38

I don't even need environment vars in some small projects, only loading of a map. Nothing common to use in clojure core libs for that is there? I'll just slurp a file and confirm it is a map

matan19:05:52

Thanks though! and I wonder what's your favorite for larger projects

ghadi19:05:39

that sure has a lot of dependencies to do something simple ^

ghadi19:05:15

@matan I like your idea of slurping in a map. In the past I've used both immuconf, and simple clojure.edn/read

ghadi19:05:55

edn/read is nice for config because you could do sophisticated things like tagged readers:

{:http {:port #env PORT}}

ghadi19:05:19

^ with that, you can use different handlers for values tagged with #env. A simple impl could read from the System/getenv, a more sophisticated one could read config from a location in etcd or consul or zookeeper

ghadi19:05:56

(edn/read {:handlers {'env (fn [form] (System/getenv form))}} rdr)

dpsutton19:05:08

wow, yeah. things that should be in a dev profile for sure

ghadi20:05:11

@dpsutton what do you mean?

dpsutton20:05:32

(defproject  cprop "0.1.10-SNAPSHOT"
  :dependencies
  [[org.clojure/clojure "1.8.0"]
   [boot/core "2.5.1" :scope "provided"]
   [adzerk/bootlaces "0.1.13" :scope "test"]
   [adzerk/boot-test "1.0.6" :scope "test"]
   [tolitius/boot-check "0.1.1" :scope "test"]]
  :source-paths
  ["src"])

dominicm07:05:16

dpsutton: Using scopes is the maven/boot way of handling dependencies. None of these dependencies are pulled into your final project

dominicm07:05:53

Only lein has decided not to use them

dpsutton20:05:50

bootlaces, boot-test and boot-check all seem like they should be dev deps, right?

ghadi20:05:11

I'm generally parsimonious about dependencies.

ghadi20:05:26

Every dependency is a relationship... gotta maintain it.

mobileink21:05:46

the arg matches no conditions?

mobileink21:05:01

try let instead of def?

noisesmith21:05:15

well, “a?” doesn’t start with “?” and it isn’t all caps

mobileink21:05:51

you know that defn and def are macros? the usual advice is to only use them at top-level.

mobileink21:05:10

@noisesmith what happens with (def x ...) when response-for is applied? does it redefine x with the new arg?

noisesmith21:05:56

right, def is totally wrong there, but it isn’t causing this particular behavior

noisesmith21:05:20

the code works (thought not at all optimal thanks to def inside defn), he’s just not providing an input that would return non-nil

mobileink21:05:18

but (response-for "A?") would work?

noisesmith21:05:53

(ins)user=> (response-for "A?")
"Whoa, chill out!"
(ins)user=> (response-for "A")
"Whoa, chill out!"
(ins)user=> (response-for "a?")
nil
(ins)user=> (response-for "?a")
"Sure."

noisesmith22:05:09

also I needed to add :refer [starts-with?] to the ns form

noisesmith22:05:21

but yeah, don’t use def like that, use a let block

mobileink22:05:23

asking 'cause i know enuff to be dangerous. def/defn - they intern things. but interning is not immutable? do it again, and atuff changes, no?

noisesmith22:05:31

with concurrency, the version that uses def will do bad things

noisesmith22:05:00

@mobileink right - def/defn mutate containers that belong to namespaces (or create them if they don’t exist yet)

mobileink22:05:11

the tricky bit for me is what def does inside a defn - i guess it does the same thing it does at top level. iow just because it's inside a defn does not mean it's "scoped" - its args will be dealt with just as if it were top level? crap i dunno how to put it. embedded def acts kinda like a fn, you give it an arg you got from the enclosing defn and the intwrned var changes. so every time you call the enclosing fn the def'ed var changes. ?

noisesmith22:05:22

also, trying it in a repl would probably take less time than typing out that question

mobileink22:05:52

not on my cellphone. ;)

noisesmith22:05:01

haha, fair enough

mobileink22:05:24

anyway repl helps but does not explain.

mobileink22:05:26

altho i gather there are phone (android) repls - any recommendations?

john22:05:33

You can't dynamically set the name of a defed thing though. So something like this won't work: (defn a [x] (def x "nope"))

noisesmith22:05:01

oh it will - but it always defines x

noisesmith22:05:11

which probably isn’t what you want

john22:05:34

oh right

john22:05:18

I was thinking of something like (defn a [x] (def (symbol (str x "-part2")) "nope")) will complain about a list not being a name.

noisesmith22:05:06

oh, yeah - there’s a way to do that properly but that’s not for beginners (and it’s usually a sign of bad design)

john22:05:52

a macro?

noisesmith22:05:05

nope, there’s a function that’ll do it

john22:05:16

in cljs?

noisesmith22:05:51

nope, it doesn’t exist in cljs

noisesmith22:05:37

I don’t mention it by name because my past experience is that I mention it and some new user is like “oh, OK I can use a namespace like a hashmap with this function…” and they end up in a mess because using namespaces like hashmaps is never a good idea

john22:05:49

yeah, bad form

john22:05:03

You can still do it with a macro in cljs, but yeah. Not a good idea to go doing that in anger.

noisesmith22:05:49

but the macro version is less harmful, because the namespace and name must be known when compiling the code

noisesmith22:05:57

so outside self-hosting, it’s constrained

noisesmith22:05:23

@john oh, it’s still possible, the mechanism is different, I’ll message it to you 😄

vitruvia23:05:18

but how do I define a new variable within a function if I can only use it at top level?

vitruvia23:05:18

And yes I just realized I used startswith when I to use ends with, thanks @noisesmith xD

john23:05:10

@vitruvia folks usually put their data in other atoms defined at he top level. Then other callers at whatever level can access the data in the atom. Was there another use-case you were looking for?

vitruvia23:05:57

no, I just didn't know how it was usually done in closure. Thnaks @john

john23:05:50

In your example above, you don't appear to need global access to x. So you'd want to use something like ... (let [x (apply str (filter #(Character/isLetter %) phrase))] (do-stuff-with-x x)) ...

vitruvia23:05:27

indeed I don't need global access. Thanks!