beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
2021-03-05T05:38:21.259500Z

i wonder how to make a "MiXeD CaSe" , upper : for odd, lower : for even?

valerauko 2021-03-05T05:42:46.259900Z

Is there a way to get reflection / boxed math warnings excluding dependencies? Putting the globals in project.clj includes dependencies, which is a lot of noise. set!ing them in the main ns seems to be too late and I get no warnings

phronmophobic 2021-03-05T05:58:51.260400Z

are you working at the repl or running from the command line?

phronmophobic 2021-03-05T05:59:18.260600Z

at the repl, I can usually just set! in the main namespace and reload the buffer

phronmophobic 2021-03-05T06:01:16.260800Z

at the command line, I would probably just do something like:

clj <my run args...> 2>&1 | grep 'Reflection warning' | grep "<filename I care about>" > warnings.txt

seancorfield 2021-03-05T06:04:55.261800Z

@adrianimanuel take a look at cycle and think of it used on the functions you want to apply to elements of your string

seancorfield 2021-03-05T06:07:17.262100Z

Like so:

user=> (require '[clojure.string :as str])
nil
user=> (str/join (map (fn [f c] (f (str c))) (cycle [str/upper-case str/lower-case]) "mixed case!"))
"MiXeD CaSe!"
;; or:
user=> (str/join (map (fn [f c] (f c)) (cycle [#(Character/toUpperCase %) #(Character/toLowerCase %)]) "mixed case!"))
"MiXeD CaSe!"
user=>

1
Hagenek 2021-03-05T09:16:00.265Z

This made my day a little better, such a fun way to solve this problem:grinning:

2021-03-05T06:13:45.262300Z

thank you so much, I'll digest this code... unfamiliar with cycle yet

2021-03-05T06:21:02.262500Z

now I just learn that we can use map like that as well šŸ˜²

seancorfield 2021-03-05T06:25:02.262700Z

clojure.core is huge -- even after over a decade of using Clojure, I'm still finding new functions (or new ways to use old functions).

valerauko 2021-03-05T06:27:06.262900Z

I'm doing the grep way right now. I was hoping for something more... uh, refined?

phronmophobic 2021-03-05T06:37:25.263100Z

afaik, warnings from warn on reflection can only be read from stderr, so any option will have to read from stderr. you could do something like https://github.com/clojure/clojure/blob/cbb3fdf787a00d3c1443794b97ed7fe4bef8e888/test/clojure/test_helper.clj#L123 if you wanted to programmatically gather warnings. It's possible that there's a tool or IDE that already does that, but I just common tools like grep ĀÆ\(惄)/ĀÆ

seancorfield 2021-03-05T06:44:01.263300Z

FWIW, I put (set! *warn-on-reflection* true) in every source namespace, after the ns form as a matter of course these days.

seancorfield 2021-03-05T06:44:18.263500Z

(I often put it in test namespaces too)

Joel Ambass 2021-03-05T09:20:00.267800Z

Hey there, total Clojure noob here! I'm reading a book called "7 concurrency models in 7 weeks" where Clojures concurrency model is one example. Now there's one thing which isn't really explained that well and where I didn't really find a quick explanation about what it exactly does under the hood (probably I just don't know where to look at). The book states that: > As its name suggests, ensure ensures that the value of the ref it returns wonā€™t be changed by another transaction. Itā€™s worth comparing this solution to our earlier lock-based solutions. Not only is it significantly simpler, but because itā€™s lockless, itā€™s impossible for it to deadlock. Now I don't quite understand yet how this is achieved

2021-03-05T09:37:15.268700Z

you can imagine (ensure r) as being the same as (alter! r identity)

2021-03-05T09:40:18.272700Z

I wouldn't focus so much on ensure, it is optimization basically, if it didn't exist there other ways to avoid, uh, I guess it is read skew

raspasov 2021-03-05T09:40:30.273100Z

@ambass.joel I always found that for explaining specific Clojure concepts like concurrency around refs/agents the old https://www.amazon.com/Clojure-Programming-Practical-Lisp-World/dp/1449394701 is hard to beat; while dated in certain aspects, I found the book sections about refs/agents quite excellent and they are still pretty much 100% valid (no significant changes in Clojure in those areas as far as I know)

danielneal 2021-03-05T09:41:42.274700Z

Is there an alternative to merge that will ignore nils. I got (merge-with #(or %1 %2) {:a 1} {:a nil}) ;=> {:a 1} but wondering if there is something more idiomatic

Ben Sless 2021-03-05T09:42:53.276700Z

(into to (remove (comp nil? val)) from)?

raspasov 2021-03-05T09:42:54.277Z

@ambass.joel another piece of practical advice around concurrency in Clojure is also ā€œstick to (atom ā€¦) for vast majority of casesā€; way simpler and usually thereā€™s a way to solve your problem with just atoms;

Joel Ambass 2021-03-05T09:43:02.277200Z

Thanks for your answeres! I have to admit that I'm (not yet) ready to look deeper into clojure as a language itself so I'm more interested on a conceptional level for now šŸ™‚ So what I'm basically trying to understand is how ensure guarantees that other transactions don't change the ref ? Maybe there's also some missunderstanding of the guarantes ensure brings.

2021-03-05T09:43:32.277700Z

ensure doesn't really do that

Joel Ambass 2021-03-05T09:43:34.277900Z

Jup that's also mentioned and I think it makes a lot of sense for 99% of the cases.

danielneal 2021-03-05T09:43:45.278300Z

I guess, thanks

2021-03-05T09:43:51.278700Z

the transaction does it, ensure just makes sure the given ref is part of the transaction

2021-03-05T09:44:13.279400Z

clojure does mvcc

2021-03-05T09:45:03.280900Z

meaning there are multiple versions of each ref, associated with each concurrent transaction, and one of those versions gets committed, and other transactions retry

2021-03-05T09:45:54.282200Z

alter! or ref-set! in a transaction mark a ref as part of that transaction, just reading the value of a ref doesn't

2021-03-05T09:46:17.282900Z

ensure is a way to read the value and mark it as part of the transaction

Joel Ambass 2021-03-05T09:46:18.283Z

Got it! That makes a lot of sense.

raspasov 2021-03-05T09:47:18.283600Z

Yes, thatā€™s correct. In 8 years of Clojure, I donā€™t think Iā€™ve used (ensure ā€¦) even once šŸ™‚ And Iā€™ve written some decently optimized/concurrent code with it; I can relate to the curiosity just for learningā€™s sake though.

šŸ˜ 1
Joel Ambass 2021-03-05T09:52:00.285800Z

I think the part that I was missing is that the other transactions would retry. Kinda stupid question but how does it determine if it needs to retry? I guess it needs to compare it's local state of the ref with the now global state or something like that? When does that happen? (Probably still some misunderstanding and/or mixing of thoughts on my side šŸ™‚ ) EDIT: I guess it's the dosync function that does that right?

2021-03-05T10:00:05.288300Z

the dosync causes the code in its dynamic extent to run in a transaction

2021-03-05T10:02:09.290200Z

I believe basically each ref has a version number, and when a ref is modified for the first time in a give transaction, the ref and its version number are recorded in the transaction, and then when it is time to commit the versions numbers are compared to the current versions, and if the ref has been modified since, then the transaction is retried

Joel Ambass 2021-03-05T10:04:49.290900Z

Ah ok so similiar to Postgres transaction ids in that sense. But does the dosync block actually syncronize (I think it doesn't right?) so how is it guaranteed that there are no race conditions?

2021-03-05T10:07:30.292400Z

I guess reading the value of a ref does make it part of the transaction in a limited sense, in that it causes the transaction the cache the value read and return in for subsequent reads, so all reads in a transaction get the same value

2021-03-05T10:08:46.293500Z

it is called a LockingTransaction because it is built on locks

2021-03-05T10:10:44.294300Z

the only mutable things are the refs, and you can only mutate the refs in transactions, which are real transactions (ACI but no D)

Joel Ambass 2021-03-05T10:13:57.297100Z

So where does the locking/synchronization happen? Is the whole transaction synchronized or just when we ensure or alter the refs ?

2021-03-05T10:14:11.297300Z

none of those

2021-03-05T10:14:44.298100Z

the locking happens when a transaction commits, which is after the body has run

2021-03-05T10:16:05.299600Z

(technically refs all have a readwritelock, and the read lock may be held briefly while reading)

Joel Ambass 2021-03-05T10:16:21.300Z

So it gets the global state of all the ref s and compares them to their local state (with a semaphore around the checking of those refs)

2021-03-05T10:16:33.300200Z

no

Joel Ambass 2021-03-05T10:16:36.300400Z

šŸ˜„

2021-03-05T10:16:43.300600Z

no globals

2021-03-05T10:16:57.301100Z

it just checks the state of the refs involved in the transaction

Joel Ambass 2021-03-05T10:17:12.301400Z

against what?

2021-03-05T10:17:31.301700Z

against themselves

2021-03-05T10:18:12.302500Z

if they haven't been modified since the body of transaction ran, the transaction can be committed, otherwise it needs to be retried

Joel Ambass 2021-03-05T10:19:20.304500Z

Yes that I understand but how does it know that they have been modified? I guess they have their local cached copy of them (with a given transaction version number or something) but what does it use to see if somebody else have modified them?

2021-03-05T10:19:44.305Z

the ref has a version number, not the transaction

Joel Ambass 2021-03-05T10:20:02.305600Z

Yes sorry that's what I mean with that šŸ™‚

2021-03-05T10:21:04.306800Z

so the first time a ref is touched in a transaction, it will store in the current transaction "my version is 5", and then at the commit point, if the ref says "my version is 6", then you need a retry

2021-03-05T10:21:26.307600Z

if it says "my version is 5" at the commit point, you can commit and increment the version on that ref

Joel Ambass 2021-03-05T10:22:11.309100Z

Ok, that's what I basically meant with comparing the global state of the ref (current version number) with the local one (the one it had at the start of the transaction)

2021-03-05T10:22:16.309300Z

this is all based on my fuzzy recollections, at a certain point the answer to "but how does it do that?" is "it does the stuff in the code there" which is what I linked to

Joel Ambass 2021-03-05T10:23:43.311100Z

Yeah no that's the level I wanted to get answers to. If I had a bit more knowledge and time to invest I would have tried to get that from the source but I'm really thankful for your time and explanation! It certainly helped a lot to understand the concept and important details of it better šŸ™‚

sb 2021-03-05T10:40:14.312500Z

if I have a lib which works normally (via shadow-cljs) https://www.npmjs.com/package/jsonwebtoken I would like to do a jwt sign.. with rs256 in clojurescript, my code is:

(def creds {:client_x509_cert_url "<https://www.googleapis.com/robot/v1/metadata/x509/54354354@t.iam.gserviceaccount.com>",
            :token_uri "<https://oauth2.googleapis.com/token>",
            :type "service_account",
            :private_key_id "58f854354354354330b0fd3",
            :auth_provider_x509_cert_url "<https://www.googleapis.com/oauth2/v1/certs>",
            :client_email "<mailto:agapi@ga-balbla.com|agapi@ga-balbla.com>",
            :client_id "11765353534543507207",
            :project_id "ga-v4-auth-test",
            :private_key "-----BEGIN PRIVATE KEY-----
               MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCeHLXyO+bOEWyq
               bYNKVGMclwrMFq8IdKrUjdDg+1PT9OK4d3k2Xv7jpprjI2dSNpuLm26JIvcE0hF2
               smk4mOXKzrf79v+lPLM+5GKv6YBW7TlZfJBzIxtPMLhiZBMKNUaYZSQsldJiTISM
               ...............................................................
               dKmIUpzZ4Y1FnRVx6FCENN0JlzOaGa2PhGUZfLisXVwkWyXinyuElyaUGXo6BI64
               fazS98F6ZtU8GhElnKO43usa5bcQareDtan9N1m1S8g4Tr3x7daPbhiVAoGAU+AS
               eIBqm7zMxM3RE57+GH59o2SvVD94QpDn9GbHUs2IuKE4NTrrdp79YBphRVpyb6R8
               jeJfTr8FM3zLzUeBgRxuY9Jus6wpM5gXYzw+v8NCjwb9dsD0BSkLmRPXe1L6pwAr
               0c3lQkcB1sDwIxAIE1noM/6Ex+UdESLGHi0HXoECgYByffIreMTVaUAWhMWh0dBX
               /2eVMxOibNGtoiCWn6f3d8zKFJb4ut7NCC5fZHzUccGPyJ8hVFi1BWvJjmIIYM0M
               ZzeXhzkqttFA9uT5irrRD071tKjdF/hXkJ510RdjSVgOd7z/YmzPxR2mpOS2LGH0
               Mld1BOLpH/p+DkED5p3+WA==
               -----END PRIVATE KEY-----
               ",
            :auth_uri "<https://accounts.google.com/o/oauth2/auth>"})

sb 2021-03-05T10:40:48.313Z

and when I run:

(jwt/sign (.stringify js/JSON (clj-&gt;js {:foo "bar"})) (-&gt; creds :private_key) (clj-&gt;js {:algorithm "RS256"}))

sb 2021-03-05T10:41:41.313300Z

I got error: `Execution error (TypeError) at (<cljs repl>:1). Cannot read property ā€˜2ā€™ of null`

sb 2021-03-05T10:41:55.313500Z

Any idea what is the problem?

sb 2021-03-05T10:45:42.314Z

eg. this works fine: (jwt/sign (clj-&gt;js {:foo "bar"}) "sssssss")

dharrigan 2021-03-05T10:51:04.314400Z

Are you you want to be leaking a private key?

sb 2021-03-05T10:51:20.314700Z

No, as you see I modified

dharrigan 2021-03-05T10:51:29.314900Z

ah yes,

sb 2021-03-05T10:51:48.315200Z

Just I would like to show the structure of original creds

sb 2021-03-05T10:52:26.315700Z

I donā€™t know what is the problem.. I canā€™t find out/ see. Any tip welcome! :)

sb 2021-03-05T10:55:54.317200Z

Sorry! that was a false question.. I donā€™t know why didnā€™t run the first.. but now works: (jwt/sign (clj-&gt;js {:foo ā€œbarā€}) (:private_key creds) (clj-&gt;js (:algorithm ā€œRS256"))) maybe a typo

dharrigan 2021-03-05T10:56:07.317400Z

:thumbsup:

Lucy Wang 2021-03-05T15:37:31.319600Z

I have recently 4clojure really good, even after I have written quite some clojure code https://www.4clojure.com/ . Question: is there such well-organized piece-by-piece-puzzle project for frontend stuff like html & css?

Lucy Wang 2021-03-08T00:25:05.008500Z

thanks!

william 2021-03-05T16:59:20.320900Z

hey, I started using cider within a clj project. When I go to a newline between two forms, the second form is not correctly indented (I didn't have this problem in my cljs projects). Who's controlling that indentation?

william 2021-03-05T17:00:11.321600Z

for example, if I have:

(defn something [param]
  (let [data (:key param)] | (prn data)))
and I issue a newline where | is, I get:
(defn something [param]
  (let [data (:key param)]
(prn data)))

dpsutton 2021-03-05T17:07:09.323700Z

so it works on my machine. but here's how i can diagnose things. i copied that, put my cursor where the pipe was and hit enter and it worked. then i undid that, and hit C-h c [enter] which asks emacs to tell me what its calling when i hit enter. that said newline. So i'm gonna read the documentation for newline with C-h f newline which has the following documentation > If ā€˜electric-indent-modeā€™ is enabled, this indents the final new line that it adds, and reindents the preceding line. To just insert a newline, use M-x electric-indent-just-newline. So now it seems it depends upon electric-indent-mode which is the thread i would look into now

dpsutton 2021-03-05T17:08:51.324100Z

C-c v electric-indent-mode tells me this is on for me

dpsutton 2021-03-05T17:10:20.325900Z

a bit of hint for perhaps some arcane commands here: C-h starts asking for help. C-h c is for "character", what happens when i press whatever. in this case it was the enter key. C-h f gets documentation about a function (`f`). I asked for documentation for what happens when i run the function triggered by the key i looked up. And then i checked out a variable with C-h v on electric-indent-mode and it told me some documentation about it and that it was enabled

dpsutton 2021-03-05T17:10:49.326400Z

but from all that, i would call the function (elecric-indent-mode) and then see if that fixes it

william 2021-03-05T17:21:48.330100Z

thanks a lot for the details, @dpsutton! Now, when I hit a newline I'm actually calling lispy-newline-and-indent-plain, which in my case forwards to newline-and-indent , which, besides being advised to continue a comment, in general should behave like TAB. But also, TAB, which calls indent-for-tab-command, which should ultimately call indent-relative. But even indent-relative is just sending some tabs, not aligning it the way I would expect. Also, it still works in another cljs file, which made me think that it's an issue with how my project is configured.

dpsutton 2021-03-05T17:23:13.331400Z

as far as i know none of this should really involve the project itself. there is a small bit that could ask nrepl for how to indent things since vars can have indention settings but i don't think that's what's going on here. all of this behavior doesn't take into account your project at all

dharrigan 2021-03-05T17:23:50.332Z

Not sure if there is anything like http://4clojure.org for frontend Clojure stuff, but you may get something from this set of tutorials by practicalli

william 2021-03-05T17:23:53.332200Z

also, strangely, it seems to be indenting properly other parts, and just break in this particular case

dharrigan 2021-03-05T17:23:54.332300Z

https://practicalli.github.io/clojure-webapps/

dharrigan 2021-03-05T17:24:01.332500Z

Maybe that might help?

dharrigan 2021-03-05T17:24:37.332900Z

There's a set of tutorials and videos about constructing a simple web-based banking system.

dharrigan 2021-03-05T17:25:07.333100Z

It's not complete as far as I can tell, but it may help to get you started

dharrigan 2021-03-05T17:25:39.333300Z

This is also a good source of information about using figwheel-main

dharrigan 2021-03-05T17:25:40.333500Z

https://figwheel.org/tutorial.html

william 2021-03-05T17:34:13.335200Z

hah: the error seems to be in: clojure-indent-function as I get clojure-indent-function: Wrong type argument: number-or-marker-p, nil in my messages buffer. The cause might be that I started using emacs 28, and this broke something

dpsutton 2021-03-05T17:34:15.335300Z

are you using paredit?

dpsutton 2021-03-05T17:35:33.336700Z

ah. well you have some fun digging to do. and it sounds like you have some decent experience with emacs. so hard to tailor advice with the vast range of experience that might be in here: first day using emacs vs maintainer of a popular emacs library just new to Clojure or CIDER

william 2021-03-05T17:37:01.337600Z

right, I'll try to poke around, and in case probably just confirm that I don't have this problem in emacs27, and maybe open an issue. But thanks for the help! šŸ™‚

šŸ‘ 1
grazfather 2021-03-05T20:06:07.338400Z

how should I structure this?

(defn get-current-branch
  []
  (let [output (-&gt;&gt; (sh "git" "branch")
                    :out)]
    (if-let [branch (re-find #"\* (\w+)" output)]
      (second branch)
      (second (re-find #"\* \(HEAD detached at (\w+)\)" output))
      )))
Basically the second case of the if-let sucks

seancorfield 2021-03-05T20:07:33.338700Z

I'd probably use a single regex with that extra string part being optional.

seancorfield 2021-03-05T20:08:39.338900Z

(let [[_ _ branch] (re-find #"\* (\(HEAD detached at )?(\w+)" output)] branch) -- something like that?

seancorfield 2021-03-05T20:11:40.340Z

Although \w+ will not match - and I often have dashes in my branch names.

seancorfield 2021-03-05T20:12:02.340200Z

dev=&gt; (let [output "* master"] (let [[_ _ branch] (re-find #"\* (\(HEAD detached at )?(\w+)" output)] branch))
"master"
dev=&gt; (let [output "* (HEAD detached at master)"] (let [[_ _ branch] (re-find #"\* (\(HEAD detached at )?(\w+)" output)] branch))
"master"
dev=&gt; (let [output "* WS-12677-refactor-hubble-model"] (let [[_ _ branch] (re-find #"\* (\(HEAD detached at )?(\w+)" output)] branch))
"WS"
dev=&gt; 

borkdude 2021-03-05T20:12:09.340500Z

isn't he matching a SHA?

grazfather 2021-03-05T20:12:18.340800Z

oh, and I didnā€™t think of destructuring instead of using secon

seancorfield 2021-03-05T20:12:21.341Z

Not from git branch.

grazfather 2021-03-05T20:12:31.341400Z

@borkdude I am matching a branch or detached head, in which case i need to get the hash

grazfather 2021-03-05T20:12:39.341800Z

i can expand the class to include dashes

phronmophobic 2021-03-05T20:12:47.342100Z

depending on how much you know about how git works and how much you like parsing git commands, there's also https://www.eclipse.org/jgit/

seancorfield 2021-03-05T20:12:57.342500Z

@grazfather Note that with the optional detached head stuff, you need to return the third item, not the second.

borkdude 2021-03-05T20:13:04.342900Z

Right, I usually do it like this nowadays: [A-Za-z_-]

grazfather 2021-03-05T20:13:16.343100Z

you can have dots in git branches, too šŸ¤Æ

borkdude 2021-03-05T20:13:29.343500Z

About jgit: even the clojure tools CLI is stepping away from that now by shelling out to git, so you're in good company :P

sebastian andersen 2021-03-05T20:13:43.343800Z

how come #{1 2 3 4} evaluates to #{1 4 3 2} but, #{1 2 3 4 5} evaluates to #{1 4 3 2 5} ?

phronmophobic 2021-03-05T20:14:04.343900Z

is that to avoid dependencies or is parsing git commands actually easier?

borkdude 2021-03-05T20:14:19.344100Z

avoid dependencies, fix a list of issues

borkdude 2021-03-05T20:14:26.344300Z

#tools-deps for more info

borkdude 2021-03-05T20:15:06.344500Z

I think git itself has options to emit output that is easier to parse for some use cases

šŸ‘ 1
seancorfield 2021-03-05T20:16:03.344900Z

Sets are unordered.

seancorfield 2021-03-05T20:16:12.345100Z

Hash maps are also unordered.

borkdude 2021-03-05T20:16:14.345200Z

@smith.adriane Here's the list: https://clojurians.slack.com/archives/C6QH853H8/p1614809707124400

šŸ‘ 1
seancorfield 2021-03-05T20:17:14.346300Z

If you walk along a set or a hash map (via printing or any sequence operation), you should pretty much assume you'll get the elements in a random order.

āœ… 2
sebastian andersen 2021-03-05T20:25:18.348500Z

Oh, okay, how come sets aren't ordered?

ghadi 2021-03-05T20:25:39.348900Z

because sets have no order

šŸŽÆ 1
ā˜ļø 2
ghadi 2021-03-05T20:25:54.349200Z

nor do maps

ghadi 2021-03-05T20:26:27.350100Z

(despite other languages' implementation choices)

2021-03-05T20:30:26.353800Z

meaning, sets in mathematics have no order.

šŸ‘ 3
pavlosmelissinos 2021-03-05T20:31:10.354700Z

> Two sets are equal if and only if they have precisely the same elements. > the order in which the elements of a set are listed in roster notation is irrelevant, so {6, 11} is the same set as {11, 6}, and {2, 6, 4}, {4, 2, 6}, {4, 6, 2}, {6, 2, 4} or {6, 4, 2} all represent the same set https://en.wikipedia.org/wiki/Set_(mathematics)#Roster_notation

2021-03-05T20:33:11.356800Z

There are implementations in Clojure of sets and maps that do have various kinds of ordering guarantees, e.g. sorted by key/element given a comparator function (`sorted-set`, sorted-map built into Clojure), order by insertion, etc. if you really want one, but you often don't.

2021-03-05T20:33:48.357300Z

Some of those variants are linked from the Clojure cheat sheet, which can be useful for other reasons, too: http://jafingerhut.github.io/cheatsheet/clojuredocs/cheatsheet-tiptip-cdocs-summary.html

sebastian andersen 2021-03-05T20:36:48.360500Z

But what is the point of sets in math then?

2021-03-08T14:15:25.034700Z

they are specifically (and only) an object that is defined by what is (or equivalently what isn't) a member use them in clojure when the role a piece of data plays is to keep track of membership (for example when called as a function they act like a membership test)

(ins)user=&gt; (def special #{1 2 3})
#'user/special
(ins)user=&gt; (special 1)
1
(ins)user=&gt; (special 5)
nil

2021-03-05T20:37:10.361100Z

Those others aren't quite as "first class" as the default unordered sets, e.g. if a library for reading a JSON file, XML, etc. can return a Clojure map, it depends upon who developed that library whether they thought to return one of these variants of sets/maps that preserve read order, or not.

2021-03-05T20:37:33.361600Z

To represent which of some domain of values has some property, versus which do not.

2021-03-05T20:38:16.362300Z

e.g. this set of symbols appears in this program, and any not in the set, do not appear in the program.

2021-03-05T20:39:18.363600Z

This set of records appears in this table of a relational database, any others do not.

2021-03-05T20:41:52.364900Z

As far as a map goes, consider a map used to describe properties of a person. Do you have brown eyes first, and black hair second, or vice versa? Answer: You have both simultaneously.

sebastian andersen 2021-03-05T20:43:23.366500Z

Yeah, that's also how I Iooked at maps, they remind me a bit of js objects.

2021-03-05T20:45:08.368200Z

Some others who want to read, process, and write out modified JSON files that are similar to the input file might ask exactly the same kind of question about maps, if maps were used to represent the JSON data read, i.e. why don't they preserve read order by default? You can implement that in Clojure, but you might have to ensure that you use a data structure other than an unordered map to represent the JSON data you read, or else the write order could be completely different.

āž• 1
2021-03-05T20:46:16.370Z

Should someone care about the order of keys in a JSON map? I have heard that some applications might actually do that, which other might say is a misuse of JSON. I don't know if there are any official answers to that question, or which applications might treat order as important there.

sebastian andersen 2021-03-05T20:49:04.373800Z

But, I haven't yet experienced needing json objects to stay in order though. I guess it would be an issue if you decided to iterate over the keys, and expect specific pairs at some point, but you shouldn't do that, since that leads to easily breakable code.

2021-03-05T20:50:05.375100Z

So, think of a mathematical set as only the keys of a JSON map. There are many use cases for representing membership in some class of values, where order doesn't matter, and shouldn't.

sebastian andersen 2021-03-05T20:52:25.376400Z

can you use a set to map a vector of maps thus filtering the maps by key to match the set?

2021-03-05T20:53:43.377400Z

I'm not sure I understand your question. In both mathematics and Clojure, the values that can be placed into a set can themselves be other sets, or maps, or numbers, etc. If that doesn't answer your question, please try again, maybe with an example.

2021-03-05T20:55:43.379100Z

In Clojure, the keys of a map can be sets, or other maps, or numbers, and many other kinds of values, which can sometimes be useful. I don't think JavaScript has such generality in its JS Objects as far as what keys it can have, but I'm no JavaScript expert.

sebastian andersen 2021-03-05T20:56:42.379800Z

You sure can't do that with objects in JavaScript

pavlosmelissinos 2021-03-05T21:03:10.382300Z

@andersendigital not really sure but maybe you mean this?

(let [vector-of-maps [{:a 1, :b 2} {:b 5, :c 1} {:a 1, :b 2, :c 3, :d 4}]
      a-set          #{:a :c}]
  (map #(select-keys % a-set) vector-of-maps))

=&gt;  [{:a 1} {:c 1} {:c 3, :a 1}]

šŸ™Œ 1
sebastian andersen 2021-03-05T21:20:32.383400Z

@pavlos Yeah, that looks like what I was thinking.

1
sebastian andersen 2021-03-05T21:32:19.386Z

Given this task: Write a function,Ā `mapset`, that works likeĀ `map`Ā except the return value is aĀ set. Would you say this code is a correct answer?: Ā“Ā“Ā“clojure (defnĀ mapset Ā Ā [functionĀ collection] Ā Ā (setĀ (reduceĀ (fnĀ [final-collectionĀ item] Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā (printlnĀ final-collection) Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā (intoĀ final-collectionĀ [(functionĀ item)])) Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā [] Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā collection))) Ā“Ā“Ā“

sebastian andersen 2021-03-06T09:04:07.399100Z

Oh, I feel like you're suggesting I use an empty set instead :thinking_face:

šŸ‘ 1
phronmophobic 2021-03-05T21:37:20.386300Z

Seems like a good start. A couple notes: ā€¢ map is lazy while this implementation is eager ā€¢ the initial value for reduce is provided a vector. Is there another initial value that might simplify things? ā€¢ You're using into to add a single item to final-collection . Is there another function that might be more appropriate?

grazfather 2021-03-05T21:43:26.388800Z

Hm, is there an idiomatic way to run something before and after, but return the middle? something like with-open? Basically I am writing a script that will run a command on a certain git commit, but I want to checkout the commit where I started, so it would be like

(let [current (get-commit)
      _ (checkout commit)
       out (do-something)
      _ (checkout current)]
     out)

phronmophobic 2021-03-05T21:50:01.389300Z

try try

(let [current (get-commit)]
  (try
    (checkout commit)
    (do-something)
    (finally
      (checkout current)))) 

2021-03-05T21:51:27.390800Z

what are some general purpose debugging strategies that folks use to find errors in lazy sequences? normally i'd inspect the stack trace to see the line at which the error occurred, but if the seq is lazy, it only tells me the line at which the error was realized (i think).

2021-03-05T21:52:03.390900Z

i also tried running through the code path and replacing all calls to map with mapv, thinking that would realize the error and help me hone in on it

2021-03-05T21:52:38.391100Z

i've been warned about using concat because it can introduce the same kind of subtle, lazy bugs.

grazfather 2021-03-05T21:54:08.391300Z

Ah, nice šŸ™‚ my next question was how to make sure i checkout current if thereā€™s an issue

šŸ˜ 1
sebastian andersen 2021-03-05T21:59:32.391600Z

I have yet to learn what it means to be lazy in clojure.

phronmophobic 2021-03-05T22:00:24.391800Z

you can probably ignore that for now

sebastian andersen 2021-03-05T22:00:45.392Z

Oh okay, cool šŸ˜„

phronmophobic 2021-03-05T22:01:29.392200Z

here's a quick overview if you're interested though, http://clojure-doc.org/articles/language/laziness.html

sebastian andersen 2021-03-05T22:16:09.392600Z

Taking everything you said except for laziness into account, how does this feel?

(defn mapset
  [function collection]
  (set (reduce (fn [final-collection item]
                 (conj final-collection (function item)))
               [(first collection)]
               (rest collection))))

phronmophobic 2021-03-05T22:28:31.392800Z

looking better. I wouldn't add the first item to the initial value since that will give you incorrect* results if you passed mapset an empty collection

phronmophobic 2021-03-05T22:29:52.393Z

The hint about the initial value was more about the fact that your goal is to return a set so there's probably a better initial value than an empty vector

robertfw 2021-03-05T23:26:49.393400Z

The official answer from the JSON spec is that objects are unordered

blak3mill3r 2021-03-05T23:51:21.393600Z

In development and testing I tend to force the realization of a sequence so any bug that is only triggered later on in the sequence will be caught early. That isn't a magic-bullet of course, the tests aren't going to cover every possibility that you care about. I would say that what you're encountering is pretty fundamental to lazy sequences. However your stack trace should still be pointing out whatever code is called to generate the next element of the sequence (and that's the only thing that deserves to be called an "error in a lazy sequence"). Many times I have found that to be enough (understanding the local context surrounding an exception being thrown when generating more elements of a sequence).

šŸ™ 1