Fork me on GitHub
#beginners
<
2021-01-28
>
fullNameHere07:01:17

Given this Data structure How could I append to allbooks? (def data-base {:nameHere {:allBooks ["harry potter" "twilight" "hunger games" "hunger games 2" "hunger games 3"]} :horror ["hunger games" "hunger games 2" "hunger games 3"] :love ["twilight"] :count 3}) this works (vector (get-in data-base [:nameHere :allBooks]) "yeash") but not this (update-in data-base [:nameHere :allBooks] (vector (get-in data-base [:nameHere :allBooks]) "worked"))

didibus07:01:42

update-in takes a function which will be given the current value

didibus07:01:05

(update-in
 data-base
 [:nameHere :allBooks]
 conj
 "worked")

fullNameHere07:01:25

Thank you so much, it was driving me kinda nuts. I tried something similar, but conj was in parenthesis.

didibus07:01:23

Ya, when something takes a function as argument, you need to pass it without parenthesis

didibus07:01:18

Or you need to pass in a Lambda, so sometimes you'll see:

(update-in
  data-base
  [:nameHere :allBooks]
  #(conj % "worked"))

fullNameHere07:01:36

Yeah, that looks a lot clearer.

Faris08:01:41

Hi everyone, in Programming Clojure in the Snake game part there is this section

" 	(​defn​ head-overlaps-body? [{[head & body] :body}]
 	  (contains? (set body) head))
 	
 	(​def​ lose? head-overlaps-body?)

Test lose? against overlapping and nonoverlapping snake bodies:

 	(lose? {:body [[1 1] [1 2] [1 3]]})
 	-> false
 	
 	(lose? {:body [[1 1] [1 2] [1 1]]})
 	-> true"
I have a few questions 1. Why is lose? a def but it is called like a function? 2. Coming from a Ruby background, it seems like lose? is a function calling another function but its definition doesn’t seem to accept any arguments, how does it know it can accept arguments and also pass it to heads-overlaps-body? (which also doesn’t seem to be accepting any arguments in lose?

solf08:01:54

lose? is not a function calling another function, it's just a variable that points to head-overlaps-body? (defn foo [] 42) is roughly syntag sugar over (def foo (fn [] 42)), maybe that helps you understand the second line in your example

solf08:01:47

clojure.core/defn
 [name doc-string? attr-map? [params*] prepost-map? body]
 [name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?]
Macro
Added in 1.0
  Same as (def name (fn [params* ] exprs*)) or (def
    name (fn ([params* ] exprs*)+)) with any doc-string or attrs added
    to the var metadata. prepost-map defines a map with optional keys
    :pre and :post that contain collections of pre or post conditions.

Faris08:01:46

Thanks for your answer, I understand the answer to the first question. But for the second question, I’m still not sure how it works. How does the arguments I passed to lose? get passed to head-overlaps-body?

tvirolai08:01:31

As @U7S5E44DB pointed out, lose? is a var, essentially an alias for head-overlaps-body?. Calling lose? with arguments is functionally equivalent of calling head-overlaps-body? with them, but the name makes the idea more explicit here.

Faris09:01:08

I see! Okay thats interesting. Thanks @U5JGH2F89 and @U7S5E44DB!

raspasov09:01:34

As everybody pointed out, it is just an alias for the same exact function (effectively giving one function two names which can be used to invoke/call the function). In 7 years of doing Clojure I have never really done such a thing, so it is quite unusual style IMO.

Faris09:01:50

I’m not sure I have enough experience to comment about the style, I found it in the Programming Clojure book.

raspasov09:01:27

Technically, you can give the function any number of “aliases” like: (def my-name-1 head-overlaps-body?) (def my-name-2 head-overlaps-body?)

raspasov09:01:28

Programming Clojure is a good book, perhaps for this small-scale example it’s OK. In a real project perhaps I would consider just naming the function lose? and putting a comment like:

(defn lose?
  "We lose the game when the head overlaps the body."
  [{[head & body] :body}]
  (contains? (set body) head))

Faris09:01:10

Yeah that makes sense, thanks for the tip! :thumbsup:

raspasov09:01:37

You’re welcome 🙂

evocatus11:01:41

could you recommend a simple online REPL? Preferably one which allows to edit and run multiline scripts

evocatus11:01:36

probably, but I still don't understand how to run a script there, only found the shape drawing tutorial

evocatus11:01:51

oh, it's like Jupyter notebook and I need to press Enter to create an actual code block

dharrigan11:01:59

Here's a new one that popped up recently

dharrigan11:01:06

It'll allow you to type in scripts and execute.

delaguardo11:01:06

there is another one, but it is not “online” you have to manage it itself - http://gorilla-repl.org/start.html

👍 3
dharrigan11:01:15

And of course, there is , although you'll need to sign up.

evocatus13:01:23

tried to run gorilla-repl and it doesn't work

evocatus11:01:03

clj/cljs - doesn't matter

agata_anastazja (she/her)13:01:46

Hello, I am trying to test that if there is an invalid input there will be an ExceptionInfo using thrown-with-msg?``

agata_anastazja (she/her)13:01:02

let’s say

(defn validate-input [input]
   (if true
     (throw (ex-info "invalid input" {:input input}))
     nil))

agata_anastazja (she/her)13:01:47

(deftest input-validation
  (testing "when validating"
    (is (thrown-with-msg? ExceptionInfo #"invalid input"
                          (validate-input "input"))))

agata_anastazja (she/her)13:01:15

it’s saying that ex-info returns an error dictionary instead of actual error

agata_anastazja (she/her)13:01:48

so what would be a better test for this scenario?

Alex Miller (Clojure team)13:01:55

that code looks right to me (except input-validation is missing an end paren)

👍 3
🎉 3
agata_anastazja (she/her)13:01:56

yes, the bracket is there in the original file. I just took one test out of deftest, that’s why it was missing here.

Alex Miller (Clojure team)13:01:25

are you sure your repl state matches your code?

agata_anastazja (she/her)13:01:56

ok more context

expected: (thrown-with-msg? ExceptionInfo #"invalid input" (convert "dsfds"))
  actual: #error {
 :cause "It is possible to parse only numbers from 0 to 1000"
 :data {:input "dsfds"}
 :via
 [{:type clojure.lang.ExceptionInfo 
   :message "invalid input"
   :data {:input "dsfds"}
   :at [numerals_kata.core$validate_input invokeStatic "core.clj" 13]}]
 :trace [[ .... ]]}

agata_anastazja (she/her)13:01:09

this is what the test returns 🙂

Thor13:01:00

for what it's worth, your first code sample runs fine for me, and passes (after adding a closing paren, that is).

👍 3
parrot 3
clyfe13:01:18

issue is: #"invalid input" does not match "It is possible to parse only numbers from 0 to 1000"

👍 3
🎉 3
clyfe13:01:38

Looking at that error there.

agata_anastazja (she/her)13:01:08

yes, I was checking for different strings!

agata_anastazja (she/her)13:01:07

I just spent 20 minutes looking at a string that was almost right….

duckie 6
andy.fingerhut14:01:12

A lot of programming experience is these kinds of 20-minute episodes, that in future lead you to ask different questions and check different things when things are going wrong, and the next time it will probably be less than 20 minutes 🙂

🎯 15
6
agata_anastazja (she/her)14:01:38

@jaihindhreddy by the way, hello to this amazing mentor from exercism!

👋 3
otfrom16:01:13

👋

👋 3
otfrom16:01:37

Is there a function similar to transduce or reduce that calls the completing 1-arity of a reducing step function?

otfrom16:01:00

Something like (rf (reduce rf source-seq))

otfrom16:01:29

I've been solving by doing this but it feels wrong: (transduce (map identity) rf source-seq)

3
hiredman16:01:59

The identity transducer is just identity, you don't need to map it

👍 3
Jeff Evans16:01:12

from here: https://guide.clojure.style/#body-indentation why is this good?

(when something
  (something-else))
while this is bad?
(filter even?
  (range 1 10))
is it simply because the (something-else) part is the body arg of the when macro?

dpsutton16:01:37

that guide is entirely subjective and just some people's opinions. I happen to agree with this one though. the when establishes a kind of context that (something-else) is executed in. for filter the args are of equal importance so I like them to be aligned.

clyfe16:01:33

when is macro, filter is function

Jeff Evans16:01:59

right, but even this style guide uses this language: “Vertically align function (macro) arguments spanning multiple lines.”

Jeff Evans16:01:15

it seems to elide them, at least in my reading

dpsutton16:01:41

some people do like that style of arguments staying to the left as far as possible as it can prevent lines from getting too long. I much prefer the alignment as it makes visually scanning the forms easier but sometimes it does get tedious in line length

clyfe16:01:52

vertically align both, but macros get 2 spaces

dpsutton16:01:39

(when true
  (foo)
  (bar))

;; horrendous
(when true
      (foo)
      (bar))

dgb2316:01:03

with if ?

dgb2316:01:06

also what do people think of aligning associative forms (maps)? I almost never see it. When looking at the fulcro tutorials I saw Tony Kay doing it and I immediately copied it.

clyfe16:01:39

Don't align. Better git history, and more compact code (at the expense of visual rhythm). Same for let bindings.

dgb2316:01:13

Ou right! I get it, you get formatting commits this way obviously

dgb2316:01:20

I dislike those too

pavlosmelissinos16:01:09

git diff has the -b flag though, so diffs can look essentially the same, whether you align maps or not. https://git-scm.com/docs/git-diff#Documentation/git-diff.txt--b

👍 3
dpsutton16:01:20

love to read it hate to see a diff where a single line changes the entire map. same with binding forms in let. those are the major arguments on each side. where you land on that seesaw is pretty personal and not standardized from what i can tell

👍 3
clyfe16:01:14

@jeffrey.wayne.evans so the answer is "the 2nd is bad because looking at it does not convey it's a fn call (as opposed to a macro, which it isn't)"

Jeff Evans16:01:02

thanks. I imagine this becomes automatic over time, but I also presume some editors are aware of this magic and can actually follow it

Jeff Evans16:01:27

I mean, source and doc are always at the ready

dpsutton16:01:52

in cursive control-q or f1 are amazing. a nice little popup of the source along with clojure-doc examples

3
Jeff Evans16:01:00

wait, you use Cursive too? 😆

Jeff Evans16:01:46

hell, even mouseover seems to get you that

dpsutton16:01:51

i do every now and then. i have a paid license because its really great software. If i did more interop i might look at switching or having it more at hand. its interop story is top notch

dpsutton16:01:05

emacs can't compete with cursive's and intellij's java knowledge

clyfe16:01:23

"with clojure-doc examples" you say?

dpsutton16:01:24

> hell, even mouseover seems to get you that what's a mouse?

😀 3
dpsutton16:01:43

yup. really slick. CIDER implemented it after colin did i believe because its so handy

dpsutton16:01:38

there's also a quick peek for source which is super super nice but i forgot the key binding at the moment

dgb2316:01:19

I think Go did it right. They only have 1 way to format things, no configuration. The only sensible alternative is to individually format during development, while the checked in code is formatted by the “one true way” (or not at all). I don’t see the cost-benefit there though.

Alex Miller (Clojure team)16:01:18

I formatting lisps is inherently harder because the syntax is more uniform but the semantics vary more

3
Alex Miller (Clojure team)16:01:30

that's counter-intuitive

dgb2316:01:43

That makes sense. The syntax doesn’t express as much. It’s essentially an AST.

Alex Miller (Clojure team)16:01:56

invocation itself is an abstraction and thus inside calls lurk lazy/eager eval (function/macro), unstated structure (literal maps), flow control, etc

delaguardo16:01:38

https://tonsky.me/blog/clojurefmt/ there is an alternative opinion on the formatting rules

danieroux17:01:18

I use these. They stay out of my way. That makes me happy.

delaguardo16:01:30

in nutshell — there are just two rules: • Multi-line lists that start with a symbol are always indented with two spaces, • Other multi-line lists, vectors, maps and sets are aligned with the first element

dgb2317:01:55

Recently there was a question of suitability of Clojure for certain types of computation. One of the downsides that was mentioned was higher memory pressure. But two performance upsides of FP are easier parallelisation and caching/memoization, since we’re dealing with (pure) functions in much larger quantities. How naive is it to think that it could be beneficial to skew to scaling vertically rather than horizontally given these tradeoffs? AKA requesting/using more cores and more memory, while optimising code to be concurrent, with heavy use of memoization (at the right places) instead of building smaller pieces that are scaled more horizontally with more machines (and more IO)?

noisesmith18:01:33

that's the long term dream of much fp lang development (it's what haskell banks on especially), it's still a strategy and still has trade offs though

noisesmith18:01:41

(to be clear I wasn't saying "don't use clojure because it uses too much RAM", but when prompted for use cases where you wouldn't use clojure I listed some criteria, and if you meet multiple criteria clojure might be an unpragmatic choice)

noisesmith18:01:50

in real world cases these trade offs increase complexity of code for high performance in a specific use case the drawback here (generally) is that your code is harder to write and read, and outside the specific target case it is worse than the naiive approach

dgb2320:01:12

Thank you for those pointers!

dgb2318:01:03

Also if anyone has recommended reading about this issue I would be stoked!

phronmophobic18:01:40

martin thompson has talked a lot about vertical vs horizontal. specifically, the limitations imposed by amdahl's law and little's law. He's done a bunch of interesting writing and given presentations on the subject. here's two to get started: • https://www.infoq.com/presentations/mechanical-sympathy/https://www.infoq.com/presentations/LMAX/

phronmophobic18:01:16

another notable proponent of vertical scaling is the stack overflow team: http://highscalability.com/stack-overflow-architecture

hiredman18:01:47

saying clojure has "higher memory pressure" is tricky, because it is open ended, higher than what? a better way to put might be "clojure leans hard on the garbage collector"

✔️ 3
hiredman18:01:28

although even that is problematic, because some things like everything being references and strings taking a lot of memory, are not features of clojure but of the jvm (and subject to change as the jvm changes, the string thing has gotten debatable better)

hiredman18:01:08

and the oracle and openjdk jvms ship with multiple different possible gcs, along with alternative jvms like zing shipping with their own high performance gc

hiredman18:01:15

so sort of maybe you can say something like "for a given task, among some set of programming languages, with naive task implementations, assuming the jvm languages would tend towards using more memory then others, and assuming clojure would tend to use more memory than java, would not be terrible starting assumption"

💯 3
Lyderic Dutillieux19:01:42

Hey ! I'm working on a fullstack Clojure(Script) project. The backend is a pedestal API, and the frontend is a Reagent app that calls this API. I'm wondering if an "instrospection" tool exists to introspect the backend API and generate frontend services that I could just call with apropriate params. Ever heard of something like this before ?

Daniel Stephens20:01:49

Maybe something like swagger is what you are after. Looks like there is support for ring - https://github.com/metosin/ring-swagger https://github.com/metosin/ring-swagger-ui I have only used it with Java personally, so I can't vouch for those libraries!

Lyderic Dutillieux20:01:26

Thanks, I'll have a look rn 😉

Daniel Stephens20:01:00

Turns out it's super easy to get the example going, not sure on how easy it would be to add in later:

lein new compojure-api dice-api \
&& cd dice-api/ \
&& lein ring server 

metal 3
Lyderic Dutillieux21:01:07

I've already used swagger on non-clojure projects. The lib route-swagger seems to support pedestal APIs' route definitions like here : https://github.com/frankiesardo/route-swagger/blob/8ebab45d03cb43fdec323b955f5ae4c152814d39/example/src/sample/service.clj#L279 Great. Thanks for the hint

👍 3
Marco Pas19:01:52

If i have a list of hashmaps how can i get a new list with hashmap only with the specific keys included?

(def data [{:user "foo"
            :name "foo-name"
            :age 20}
           {:user "bar"
            :name "bar-name"
            :age 24}])

[{:user foo, :name foo-name, :age 20} {:user bar, :name bar-name, :age 24}]
I want to only get the keys and values from a subset like :user and :name
[{:user foo, :name foo-name} {:user bar, :name bar-name}]

Marco Pas19:01:35

Need to refrase my question 🙂 I want to get the keys / values from the list of hashmaps

Lyderic Dutillieux19:01:22

Yes, then you can map through the list with (mapv #(select-keys % [:user :name]) data)

noisesmith19:01:50

@marco.pasopas (select-keys m [:user :name])

Marco Pas19:01:49

@noisesmith Need to refrase my question 🙂 I want to get the keys / values from the list of hashmaps..

[{:user foo, :name foo-name, :age 20} {:user bar, :name bar-name, :age 24}]
to
[{:user foo, :name foo-name} {:user bar, :name bar-name}]

dpsutton19:01:51

(map (fn [m] (select-keys m [:user :name])) data) If you can do it once you can do it many times with map

Marco Pas19:01:59

@dpsutton Thanks!! Going to digest how this works 🙂

noisesmith19:01:05

yeah, I'd avoided the specific solution (because you might already be iterating the collection somewhere), but map is what usually get used

👍 3
Marco Pas19:01:35

Thanks all for answering a real newbie question 🙂

dpsutton19:01:44

for sure. check out (doc map) (or use your editor specific commands to see documentation) for an explanation of how map works

MatthewLisp21:01:31

Clojurists, i believe you'll know how to do this easily, and i'm having trouble it's a simple transformation: [:a 1 :b 2 :c 3] -> {:a 1 :b 2 :c 3}

MatthewLisp21:01:23

just realized i can use partition to do this 😄

tschady21:01:57

(apply hash-map [:a 1 :b 2]); => {:b 2, :a 1}

noisesmith21:01:00

apply assoc would also work if hash-map didn't exist

Mark McQuillen21:01:36

Does anyone know how to deploy the static files created with Clojurescript to Heroku? I'm getting an error when I try to deploy the whole repo.

fullNameHere21:01:54

Does anyone know if their is a library that recreates this, or is similer. Its a checkbox but in the command prompt. This is an example when creating a new gatsby project. You hit enter and it puts a start by that line. I tried pretty.cli, but its really buggy for my computer.

noisesmith22:01:17

I don't think lanterna has that built in, but it has the pieces you could use to do that https://github.com/mabe02/lanterna

fullNameHere22:01:36

Ill give it a shot. I have been wanting to learn how to use java from clojure anyways. 2 birds 1 stone right.

noisesmith22:01:48

there are many options in the jvm itself to do that as well (and for the most part the only hard things about interop are that java apis tend to be worse than clojure ones and inheritance sucks)

👍 3
phronmophobic22:01:54

currently, only support for fullscreen (via lanterna), https://github.com/phronmophobic/terminal-todo-mvc

phronmophobic22:01:52

@santosx99xx, it's also graalvm compatible

fullNameHere22:01:27

Ill check this out too.

phronmophobic22:01:52

if you have any questions or run into any issues, feel free to ping me or file an issue

👍 3
sova-soars-the-sora22:01:22

Using google translate sometimes i get a result back such as "It&#39;s time"

sova-soars-the-sora22:01:32

Is there a way to turn that back into a normal apostrophe / etc?

noisesmith23:01:03

it's not a URL though, you need an HTML unescape, which seems not to be present in the vm

noisesmith23:01:11

(which I found surprising)

noisesmith23:01:50

the googles say use some random apache lib, but I can't tell you if that's even worth it

sova-soars-the-sora23:01:00

maybe it's enough to do a regex for apostrophes and that jazz

noisesmith23:01:33

a regex that matches character escapes then uses the Char constructor shouldn't be hard

sova-soars-the-sora23:01:57

a spec catalogue for christmas... how did you know??

sova-soars-the-sora23:01:38

mm the results i'm getting are the #&38; variety

sova-soars-the-sora23:01:14

i can't be the first human on the internet with this problem

noisesmith23:01:24

)user=> (Character/toString 38)
"&"

3
noisesmith23:01:30

that plus a regex

hiredman23:01:30

yes, people use the apache library

hiredman23:01:15

the jvm undoubtedly has infrastructure for dealing with this in its xml processing stuff, but who wants to deal with that

sova-soars-the-sora04:02:56

Pretty much the only one that arose was the apostrophe so... 1 regex later it's resolved XD

dgb2323:01:32

something that is incredibly frustrating about languages like JS is keeping track of all the things in your head that you need to change or not change at specific points in time, because equality checks for references and not for values and some libraries force you to think about these things. The more I write in Clojure, the more I realise how mentally taxing this is! That said, when dealing with such APIs with Clojure/Script: are there pragmatic techniques/pointers to contain this issue?

raspasov01:01:23

Yes. I would say this applies to all languages that deal mainly in references instead of values.

raspasov01:01:16

Pragmatic techniques: Isolate the scope of those mutable references to one corner of the program and don’t pass them around. If you need to pass them around: convert them to Clojure data first.

👍 3
dgb2301:01:32

That’s right, after you serialized it, it can’t hurt you anymore!

dgb2301:01:41

ty for the tip

👍 3