This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-08-13
Channels
- # announcements (27)
- # beginners (184)
- # boot (4)
- # cider (9)
- # cljdoc (1)
- # cljsrn (2)
- # clojure (208)
- # clojure-austin (1)
- # clojure-conj (4)
- # clojure-dev (20)
- # clojure-europe (15)
- # clojure-italy (66)
- # clojure-losangeles (2)
- # clojure-nl (32)
- # clojure-spec (64)
- # clojure-uk (80)
- # clojurescript (50)
- # cursive (2)
- # data-science (3)
- # datomic (17)
- # emacs (1)
- # events (6)
- # fulcro (3)
- # jobs (15)
- # juxt (5)
- # klipse (2)
- # leiningen (31)
- # nyc (3)
- # off-topic (34)
- # re-frame (2)
- # reagent (9)
- # schema (1)
- # shadow-cljs (52)
- # specter (5)
- # sql (3)
(def client {:namae "Super Co.", :location "Philadelphia", :description "The worldwide leader in plastic tableware."})
you can replace the client
var, but the map it points to is immutable
(let [{namae :namae :keys [location description] :as hello} client
namae "myName"
]
(println hello))
let introduces a new symbol
if it has the same name as one used before, it hides the old one
it never modifies values
if you want a new map that's mostly like an old one except one key, you can use assoc
@gagan.chohan no, it just hides the old one, none of the rebindings mutate the previous values
(let [a 0 a 1 a 2] a)
- that creates three bindings, only one is visible, the other two are hidden
because the name is shadowed by a new one with the same name
so, in my case, so that change in namae is reflected in hello as well, you recommend me to use assoc?
assoc returns a new map, that's the same as the old one except for the keys you provide
user=> (let [m {:a 0 :b 1} n (assoc m :b 3)] [m n])
[{:a 0, :b 1} {:a 0, :b 3}]
the general idea in clojure is that you make new immutable data structures with the modifications you need, instead of replacing or modifying the original
it depends, is anyone else already using the original? if yes, it isn't the same at all, if no, that's pretty much how we do it, yeah
@gagan.chohan this might illustrate what I mean
user=> (let [n 0 m {:a n} n 3] [m n])
[{:a 0} 3]
m still uses the original value of n, even though n itself is shadowed with a new value
it might help to think of it like numbers
x might change from 5 to 6, but you don't expect other things using 5 to change to 6
"before it gets changed" -- it doesn't get changed, it's immutable.
Getting used to immutability is one of the biggest mind shifts for a lot of folks new to Clojure.
We have a few controlled "reference types" that act a bit like variables in other languages but we use them only occasionally.
(let [{:keys [namae location] :as hello} (some_request) ])
I have some request coming, and keys are extracting the value, my main purpose is to change(new bind) value of namae, so that I don't have to change rest of code. I want to bind value of namaewhat you have there suffices to get the old value of namae and location and hello, in order to use hello
with a different value you'd want another binding, maybe hello2 (assoc hello :namae "myName")
or you could rebind hello and shadow the old one
(let [{namae :namae :keys [location description] :as hello} client
{namae "my name blabla" :keys [location description] :as hello} client
] (println hello))
VAlue of client is same as earlier
(def client {:namae "Super Co.", :location "Philadelphia", :description "The worldwide leader in plastic tableware."})
client
won't change. It is immutable.
my problem can be summed as follows:
(let [{ :keys [location] :as hello} client]
(println hello))
It prints entire value of client(and it's the same value in both cases -- the contents of client
)
Note that this {namae "my name blabla" ...
attempts to bind the value of the key "my name blabla"
to the symbol namae
user=> (let [{x "string"} {:x "X" "string" 42}] (println x))
42
See how x
binds to the value that "string"
is the key for.hello! I'm trying to understand some advice I got on exercism. My solution to creating my own reverse string function is:
(defn reverse-string [s]
(loop [s s
reversed-chars []]
(if (empty? s)
(apply str reversed-chars)
(recur (butlast s) (conj reversed-chars (last s))))))
And the advice is: "Notice that this may require walking "s" every time you want to access/drop the last character. Notice that conj is smart and adds new elements where it is most efficient for the data structure - try it with a vector [] vs a list '(). You could also use destructuring inside the loop binding to simplify the code if you used first+rest...."
Is he saying my method would be inefficient? I can change the []
to a '()
and use cons
to get the desired result but don't understand how that makes it a better function.
I'm also trying to refactor into using reduce
instead of loop/recur
per my advice I got here yesterday but struggling with that again.
The destructuring part is a struggle for me to understand too. Is he saying do something like [first & remaining] s
? I'm not sure how to reconcile that with the fact I'm using last
and butlast
I did not write that advice, but note that for a long string / sequence s, this function will take O(N^2) steps, because butlast and last take linear time to get to the end of the string/sequence.
That was my hunch at what he was getting at. I'm still learning about this O(N) stuff and definitely going to struggle with actually applying it to my algorithms.
One simple way to think of it, perhaps: butlast / last take N steps for a string/sequence of length N. So if you have a length 10 string, the first time through the loop it takes 10 steps, the next time 9, the next 8, etc. So 10+9+8+7+6+5+4+3+2+1 steps is 55. The sum from 1 to N is equal to N*(N+1)/2, which is nearly identical to (N^2)/2
To give a hint in a different direction, rather than quickly getting access to the end of the string, you can definitely instead quickly get access to the chars of the string from first to last.
Where could you put the first character in some other collection, such that at the end that other collection is the chars reversed?
ok, ok. This is great! So if I take the first thing from one collection and put it in the first thing of another collection technically it will reverse right if I keep putting more things on the front.
(defn reverse-string [s]
(loop [s s
reversed-chars '()]
(if (empty? s)
(apply str reversed-chars)
(recur (rest s) (cons (first s) reversed-chars)))))
Yes, for short strings you won't notice any significant difference in time, but give it a 100 megabyte string and there would be a huge time difference.
I made another attempt at destructuring now but my tests are taking forever so I think I've done something wrong:
(defn reverse-string [s]
(loop [[x & remaining] s
reversed-chars '()]
(if (empty? s)
(apply str reversed-chars)
(recur remaining (cons x reversed-chars)))))
I'm curious why my destructuring doesn't work. how is [[x & remaining] s]
different than using (first s)
and (rest s)
?
Have you tried debugging your failing solution with print statements, to show what the values of various expressions are through the loop iterations?
In your last non-working version, note that s never changes.
ok, interesting. I'll try and add in the print statements. I'm confused how s
doesn't change because I'm feeding remaining
into recur which should be the "new" s
I thought. Thanks for your advice and hints, this was very helpful!
macro question! i have a macro that wraps a function call and looks to see if a map with a certain entry is in a specific argument position. if it is, it uses the existing map in an inserted expression. if the map isn't there, it creates and inserts a new version of the map into the original call and uses it in the inserted expression. It looks like this (the eid
is the map I'm focused on): (wait-for (resolve-ability state side eid card targets) [...] (more-calls))
Sometimes, the eid
is created by function call within the macro call: (wait-for (resolve-ability state side (make-eid state :feature) card targets) [...] (more-calls))
. Looking at the macro-expansion, it looks like this is read as a list and not as a map. how do I check to see if it's a function within the macro and then call it to see if it's the eid
-style map I need before creating a new one or not?
macros cannot look at runtime data, only the form you are compiling
why do you think this should be a macro?
I inherited it as a macro, is the simple answer
feels like a potential mess to move it away from a macro, but potentially not
even with the example you show, where eid is pre-generated, your macro doesn't see the value of the eid, it seems the symbol eid
macros are source-in / source-out and can't use the data generated when your code actually runs
here's the macro: https://github.com/mtgred/netrunner/blob/fc443c1f636a10b689987c9265fdd23e165377a4/src/clj/game/macros.clj#L84
there's a few problems with that macro, first off ~'use-eid#
is pure cargo cult
please give me all of your wisdom, cuz I didn't write this and have found it frustrating to use
~'use-eid
would let you use a specific symbol if you want a dirty macro that uses a specific binding that user supplied code can also see
use-eid#
generates a symbol that's guaranteed not to clash with user bindings
mixing the two is just weird
makes sense
the logic is a bit weird, but it all acts properly on the symbols of the input form - it would take me a while to sort out the real problem it solves but it's one you don't need a macro for at my first sniff test
the logic is:
take an expression (`action`) and a bunch of further expressions (`expr`). wrap the expr
in a new function, and place that function in a global register bound to an eid
that's used by the action
. once action
is finished, it'll call (effect-completed eid)
, which then pulls the expr
function from the global register and executes it, thus executing the rest of the expressions
a poor-man's async
/`await` specific to this engine
thanks for the feedback, i'll try converting it to a normal function!
a pattern that clojure.core uses is functions using lambdas as args for this sort of thing, then a macro that constructs the lambdas
putting logic in functions and isolating macros to just be syntactic tends to simplify code
yeah, that makes sense. do you have any examples on hand?
with-redefs vs. with-redefs-fn
future vs. future-call
🙏 this is great, thank you
binding vs. with-bindings is almost this pattern, and I bet it was in a previous edit
The obvious solution is to write (let [eid (make-eid state :feature)] (wait-for (resolve-ability state side eid card targets) [...])))
but that feels verbose when I'm already using a macro that "hides" it for me
hello !
I have a client side app in ClojureScript, shadow-cljs, re-frame...
I am using bidi and pushy too.
I am trying add pagination to my app, but my problems is that bidi do not support query-parameters. For pagination I need to specify in the re-frame effect :http-xhrio
an uri
like this: /something?_page=123
.
My problem is that I do not know how can I get the query-parameters from the url
to dispatch events that depend on them.
Some ideas, maybe I am missing something trivial 🙂.
Thanks
the navigation data is saved into app state
maybe my option is get the query parameters from window.location.search
and parse it
So why can’t you do within the reframe handler something like:
(str “something/?page=” (get-in db [path to param]))
because when you press f5 the db is initialized and the data is lost
If it’s just a matter of waiting for the db to be populated first you can create a subscription that checks if the db is populated and if so then you can dispatch your event-fx
Hi everyone. I've got my head around quite a bit of clojure and I love it so far. My question today is: is how would I write a function (in arbitrary namespace) which creates a namespaced keyword for the ns calling the function?
There is the ::kw-name
syntax for the reader, that creates a compile-time constant keyword, but its namespace will always be the one that the keyword is written in.
namespaces are a thing to organize global names, functions are values and don't know what names point to them
Not sure if I understand your question correctly, though. You want to write a function in namespace A, and whenever it is called by a function in any other namespace B, you want the function in A to be able to figure out B at run time?
Yeah, I can use that, but until I started using namespaced keywords I had helper functions that would return the keyword that I wanted out of a map. e.g. (defn player-keyword [player] (keyword (str "player-" player))
Just trying to see if I can convert something like that to use an appropriate namespace
So at runtime you would like to create a keyword where the name is calculated by your code, and the namespace comes from the namespace the function was defined in.
Currently I'm getting back :player-1 I guess I'd like to get back :my.app.name.ns/player-1
that sounds like exactly what I'm trying to do, with one small twist... Ideally I'd like to use an aliased namespace in the namespace the function was defined in
using the same names for to organize your code and your data ties your data to you code, which is brittle because code changes often, while data often ends up at rest and in huge volumes and doesn't change
I think I'm following you @hiredman so what namespace should I put keys to my data map in?
You don't need a "real" namespace for qualified keywords...
user=> (alias 'foo (create-ns 'foo.bar.quux))
nil
user=> ::foo/player-1
:foo.bar.quux/player-1
user=>
So I'd create a new namespace just to hold the keys for my data map. Seems like an unnecessary namespace, but I think I can follow the reasoning behind it to decouple from the functions
you don't need to unless you want to use '::' which is a bit of syntax and the only thing that does tie code and keyword namespaces together
if you copy and paste the form into another context (the repl, another file, etc) you will get different results
Is there not a higher probability of collision if I use :whatever/key, than if I use :my.app.data/key
In my particular case, I don't really care. I don't think my code will currently interact with the outside world. I'm just trying to understand the thinking behind everything so that in the future I can make the best decisions.
something like :http://my.app/key might be nice
Agreed. I'll go with that. thank you for your help and also for bearing with me slightly missing the point a few times!
it is confusing because: 1. keywords have namespaces 2. code is organized in namespaces 3. those namespaces are disjoint 4. the spec docs use '::' a lot
In addition to ::bar
which is completely context-dependent, there's ::foo/bar
which is dependent on foo
existing as an alias (and being consistent). I think the latter is "less bad" than the former, but it does rely on the alias
/`create-ns` "trick" which needs to be present in every ns where you use ::foo/bar
so the alias is resolved.
But, as @hiredman says, it's really not a giant pain to just use the whole namespace -- and that makes the code clearer since you don't have to go see what the alias is...
...and the namespace in a keyword is only there to make it contextually unique, i.e., it only needs to be unique across the context(s) in which it is actually used. So inside your app you can often get away with fairly coarse granularity, such as :billing/member-id
rather than a "full" qualification.
curious about some style guide suggestions for a messy cond statement. Not sure if you are familiar with the "Bob" exercise on exercism:
(ns bob
(:require [clojure.string :as str]))
(defn response-for [s]
(cond
(and
(= \? (last s))
(= s (str/upper-case s))
(not= nil (re-seq #"[a-zA-z]" s))) "Calm down, I know what I'm doing!"
(= \? (last s)) "Sure."
(= "" (str/trim s)) "Fine. Be that way!"
(and
(= s (str/upper-case s))
(not= nil (re-seq #"[a-zA-z]" s))) "Whoa, chill out!"
:else "Whatever."))
how ugly is this?!? It successfully passes all the test but I can't see how anyone would actually figure out all that's going on here. but maybe that's just the nature of the problem/solution because it's a convoluted set of requirements?
sometimes using a let binding to pre-compute and name conditions helps
I'll definitely explore how to do that. I almost wanted to do something like that and bind it to keywords and just use keywords in the cond statement because it looks so clean.
these days I line conds up as a vertical stack
(cond case-1
result-1
case-2
result-2)
eg. for a name (let [yelling? (= s (str/upper-case s)) ...] (cond (and asking? yelling?) "Calm down, I know what I'm doing!" ...))
I used to favor
(cond
case-1 result-1
case-2 result-2)
but find it harder to deal with as the case expressions and result expressions growonce you start splitting the case's and the results over multiple lines the vertical stack is a must
yeah, I actually did this too to see how it looked with my ugly one above. maybe I combine both your suggestions
the re-seq
portions were to handle two edge test cases that basically had only numbers and non letters in them. like "4?"
and "1, 2, 3"
What do you think about that? everything else seems kind of self explanatory but not that part to me at least.
ooh maybe just come up with a good name for the binding in the let statement for that...
New and improved:
(defn response-for [s]
(let [yelling? (= s (str/upper-case s))
question? (= \? (last s))
nothing? (= "" (str/trim s))
just-numbers? (not= nil (re-seq #"[a-zA-z]" s))]
(cond
(and question? yelling? just-numbers?)
"Calm down, I know what I'm doing!"
question?
"Sure."
nothing? "Fine. Be that way!"
(and yelling? just-numbers?)
"Whoa, chill out!"
:else "Whatever.")))