beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
popeye 2021-01-12T05:36:04.014Z

I was checking documentation about do in the cheat sheet and found that it executes all the function one -by-one, but clojure is smart enough to handle execution one by one right!, what is the purpose of do then?

seancorfield 2021-01-12T05:42:21.015Z

@popeyepwr Consider if. It can only accept a single expression for "then" and a single expression for "else". What would you do if you wanted to print a message in both arms and also return a value?

popeye 2021-01-12T05:46:49.017Z

yeah, I am able to connect the dots now, if we have if and we need multiple statement to be executed then we use do

1πŸ‘
2021-01-12T06:15:50.017400Z

There's a few other places where something expect a single expression, but if you want to pass in more than one you can wrap it in a do, but if is one of the main one.

zackteo 2021-01-12T08:15:10.020300Z

Hello! How do I write a spec definition to say ::lrow must be larger or equal to ::row ? Currently have (s/def ::lrow (s/and nat-int? #(<= % max-rows) #(<= % ::row))) and

(s/def ::coord
  (s/keys :req-un [::row ::col]
          :opt-un [::sheet ::lrow ::lcol]))

2021-01-12T08:19:31.021100Z

you have to keep in mind, spec is to some degree not oriented around specing maps

2021-01-12T08:20:40.022400Z

when you define ::lrow you are specing what ::lrow should mean in every map everywhere in your program

2021-01-12T08:21:37.023300Z

you are not defining it in relation to other things it may be aggregated with, because the set of things it may be aggregated with is open

2021-01-12T08:22:44.024Z

if you have a constraint based on the relationship between things in an aggregate (::cord) you spec it on the aggregate

zackteo 2021-01-12T08:29:47.024800Z

I think I get what you mean, but is there an example of how I can do this? Understand the idea but not the syntax

zackteo 2021-01-12T08:33:41.025800Z

(s/def ::coord
  (s/and
    (s/keys :req-un [::row ::col]
            :opt-un [::sheet ::lrow ::lcol])
    (<= ::row ::lrow)
    (<= ::col ::lcol)))
Think you mean something like this? but not sure how i can refer it correctly

2021-01-12T08:43:14.026300Z

::row and ::lrow are keywords

2021-01-12T08:43:36.026600Z

<= takes numbers

2021-01-12T08:43:57.027100Z

<= returns true or false, s/and takes specs / predicates

pavlosmelissinos 2021-01-12T08:59:45.027400Z

You can use proper clojure functions in specs

pavlosmelissinos 2021-01-12T09:03:00.027600Z

Including anonymous functions. So you can have something like (s/and (s/keys ...) (fn [m] "do some operation on the map"))

pavlosmelissinos 2021-01-12T09:08:59.027800Z

Apologies, I'm on the phone. The point of the function in this case is to describe a property, not do any arbitrary operation, sorry if the above was confusing. As a more simple example, you can definitely say (s/def ::int (s/and ::number integer?))

zackteo 2021-01-12T09:31:16.029300Z

So is there a way to say that one must be greater than the other then? :o

pavlosmelissinos 2021-01-12T10:13:59.029400Z

Yes. Disregard specs for a moment. If you had a map, how would you check whether the value of key :k1 is greater than the value of :k2?

zackteo 2021-01-12T10:15:23.029800Z

(when #(&gt; :k1 :k2)
do-something))
?

popeye 2021-01-12T10:16:46.030400Z

i have defined a variable (def abc {:a "b" :c "d" :e "f"})

popeye 2021-01-12T10:17:14.030800Z

why ({:keys ["a" "b" "c"]} abc) returning nil

NPException 2021-01-12T10:18:45.031700Z

the :keys destructuring needs symbols, not strings. So try ({:keys [a b c]} abc)

pavlosmelissinos 2021-01-12T10:18:47.031800Z

#(&gt; (:k1 %) (:k2 %))

pavlosmelissinos 2021-01-12T10:18:56.032100Z

% is your map

pavlosmelissinos 2021-01-12T10:19:36.032900Z

because that's what the function expects as input, it needs the whole map to check this property

pavlosmelissinos 2021-01-12T10:20:42.034100Z

So how would you rewrite the spec now?

NPException 2021-01-12T10:20:48.034500Z

that is assuming you want to destructure. Just calling it like that is creating a new map with the key :keys and value [a b c] associated with that key. Then that map is used to lookup if anything in that map is associated with abc . To which the answer is no, since the only key is :keys .

NPException 2021-01-12T10:20:54.034800Z

Hence you get nil.

popeye 2021-01-12T10:21:19.035200Z

({:keys [a c e]} abc ) - this gave unable to resolve symbol

zackteo 2021-01-12T10:22:07.035300Z

#(&lt;= (::row %) (::lrow %))

zackteo 2021-01-12T10:22:11.035500Z

I see I see!

1πŸ™‚
2021-01-12T10:23:44.036500Z

destructuring is make sence only in some context such as let ’s binding form and argument declaration for function

NPException 2021-01-12T10:25:39.037400Z

like this

(let [{:keys [a c e]} abc]
  ;; you can use a, c, and e here
  )

zackteo 2021-01-12T10:26:11.037500Z

Thanks πŸ™‚

popeye 2021-01-12T10:26:59.038100Z

yeah got it !!! thanks @d.wetzel86 @delaguardo

1πŸ™Œ
Antonio Bibiano 2021-01-12T10:46:25.038400Z

I was doing this exercise from the braveandtrue book, the aim is to create a macro that will create a number of function that get a specific key from a map eg. c-int is defined as (defn c-int [map] (:intelligence map)) etc.. and the macro should be used like this (create-attribute-fs c-int :intelligence c-str :strength c-dex :dexterity) my solution looks like this

(defmacro create-attribute-fs
  ([] nil)
  ([fn-name key &amp; nks]
   `(conj (create-attribute-fs ~@nks)  
          (defn ~fn-name [m#] (~key m#)))))
I was not sure it would work because I thought I needed a do as a the first element of the list bit it does work, why?

Antonio Bibiano 2021-01-12T10:47:23.039200Z

I figured that it's because the elements of the list created by conj are evaluated

roelof 2021-01-12T10:57:19.040Z

πŸ™‚ I just did and finisch that one . Which chapter was that ? @antbbn

Antonio Bibiano 2021-01-12T10:58:06.040300Z

Chapter 8

roelof 2021-01-12T10:58:38.040600Z

aha, I see it

roelof 2021-01-12T10:58:51.040900Z

I did it something else

Antonio Bibiano 2021-01-12T11:00:25.041600Z

feel free to post your solution πŸ™‚

roelof 2021-01-12T11:00:27.041700Z

key is for you the function and nks the arguments

roelof 2021-01-12T11:01:00.042200Z

I could but then you would not learn anything

roelof 2021-01-12T11:01:19.042600Z

but I begin with :

(defmacro defattrs
  [&amp; assignments]

roelof 2021-01-12T11:02:07.043400Z

what can you use and have we learned to iterate trough a collection ? @antbbn

Antonio Bibiano 2021-01-12T11:04:35.043600Z

map?

roelof 2021-01-12T11:12:28.043800Z

yep

roelof 2021-01-12T11:13:15.044400Z

and I want to give you a hint I also get. Look at partition

roelof 2021-01-12T11:15:04.044600Z

@antbbn

Antonio Bibiano 2021-01-12T11:18:25.045200Z

yeah I would imagine that mapping over the partition works too, i was just curious about the need for a (do)

roelof 2021-01-12T11:19:31.045700Z

could maybe also work instead of a map. I do not know

roelof 2021-01-12T11:19:55.046200Z

@d.wetzel86 do you know if we need a do ?

roelof 2021-01-12T11:23:50.046800Z

in my solution where I use a map I do not use a do @antbbn

Antonio Bibiano 2021-01-12T11:24:30.047Z

yeah me neither

NPException 2021-01-12T11:37:44.048500Z

you will need a do for that macro. Since you are effectively returning a piece of code from a macro, and you want to do multiple things in that piece of code (any number of defn in this case), those need to be in a do.

roelof 2021-01-12T11:39:41.049100Z

??? we did not use a do but a map

NPException 2021-01-12T11:48:15.050200Z

We did splice unquote the map into a (do ...` in the end. πŸ™‚

roelof 2021-01-12T11:49:38.050900Z

@antbbn then I apolize for this error of saying I did not use a do

Antonio Bibiano 2021-01-12T12:14:20.051400Z

but my macro does define all the functions it's supposed to

Antonio Bibiano 2021-01-12T12:15:05.051800Z

that's why I was confused

roelof 2021-01-12T12:22:08.052500Z

could be, there are more ways to solve a problem

NPException 2021-01-12T12:31:02.052900Z

@antbbn what does your macro look like atm?

Antonio Bibiano 2021-01-12T12:41:24.053200Z

like here https://clojurians.slack.com/archives/C053AK3F9/p1610448385038400

NPException 2021-01-12T12:53:45.057Z

okay, your macro works, but I don't know if you intended that behaviour. Let's look at a call like this:

(create-attribute-fs c-int :intelligence c-str :strength)
That macro call expands to the following code (cleared up for better readability)
(conj
  (conj
    nil
    (defn c-str [m] (:strength m)))
  (defn c-int [m] (:intelligence m)))
So it will evaluate the defn forms, and conj the vars that they return into a sequence. Then that sequence of vars is returned.
(create-attribute-fs c-int :intelligence c-str :strength)
=&gt; (#'user/c-int #'user/c-str)

NPException 2021-01-12T12:55:43.058100Z

A question I have is if the resulting functions work with your character map from Chapter 5? So does (c-int character) work?

Antonio Bibiano 2021-01-12T13:02:18.058300Z

yep

Antonio Bibiano 2021-01-12T13:03:21.058800Z

but returning the sequence of functions might not be the intended behaviour

NPException 2021-01-12T13:04:31.059500Z

It's not a bad thing either though, so you can just roll with it πŸ˜„

Antonio Bibiano 2021-01-12T13:13:43.059800Z

ehehe all right πŸ™‚

agata_anastazja (she/her) 2021-01-12T20:19:32.064400Z

Edit: solved πŸ˜„ Hello, I have a question around repl set up in intellij with the cursive plugin. I used the lein new app app_name command, and can run the app from my terminal. I haven’t changed anything at all in the scaffolded app. When I try to run the repl, I get Error: Could not find or load main class clojure.main Caused by: java.lang.ClassNotFoundException: clojure.main and all the function names are highlighted as not resolved. Any idea what might be causing that?

R.A. Porter 2021-01-12T20:24:56.067Z

Probably best asked in the #cursive channel.

1πŸ’œ
2021-01-12T20:25:02.067300Z

What I always do when creating a new leiningen project is create it at the command line like you did, and then in IntelliJ, select File -> New -> Project From Existing Sources. That registers the project as a Leiningen project and loads all the dependencies, etc. If you didn’t do that, that might be why it’s giving you problems.

1🦜
clyfe 2021-01-12T20:25:53.067500Z

Do you have clojure in project.clj :dependencies? Ie.: [org.clojure/clojure "1.10.1"]

agata_anastazja (she/her) 2021-01-12T20:27:28.067700Z

short answer: yes

agata_anastazja (she/her) 2021-01-12T20:28:07.067900Z

long answer - here is my project.clj

(defproject comparer "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "<http://example.com/FIXME>"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "<https://www.eclipse.org/legal/epl-2.0/>"}
  :dependencies [[org.clojure/clojure "1.10.1"]]
  :main ^:skip-aot comparer.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all
                       :jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})

agata_anastazja (she/her) 2021-01-12T20:29:34.068200Z

I will try that now!

agata_anastazja (she/her) 2021-01-12T20:31:37.068400Z

actually, just looking at the file tab, there was an option to add it as leiningen project, and that did the trick!

agata_anastazja (she/her) 2021-01-12T20:31:41.068600Z

thank you!

dpsutton 2021-01-12T20:33:39.069Z

for the future, you can right click on project.clj or deps.edn files and import it

roelof 2021-01-12T21:06:50.070Z

if I want to do web developement in clojure as soon as i finished the brave book, can I then better make a leiningen or a clojure-clj project ?

roelof 2021-01-13T09:37:38.096700Z

oke

roelof 2021-01-13T09:38:07.096900Z

My ideea was to start very small. A app with 3 routes and some json parsing and hiccup

roelof 2021-01-13T09:38:47.097100Z

and no problem to start this app very small. As I look at it Luminus seems to be overkill for this app

dgb23 2021-01-12T21:11:40.070100Z

I personally just use clj and shadow-cljs. But getting familiar with leinigen is beneficial. Also for web dev have a look at: https://luminusweb.com/ And consider reading: https://www.amazon.com/Web-Development-Clojure-Build-Bulletproof/dp/1680500821

clyfe 2021-01-12T21:30:39.070300Z

clj; back or front -end, or both?

seancorfield 2021-01-12T21:36:01.070500Z

Here's a small (server-side) web app that uses the Clojure CLI and deps.edn: https://github.com/seancorfield/usermanager-example -- I would suggest making sure you understand how this works and that you can modify and enhance it yourself before trying to work with Luminus (or the Web Development book). Luminus is a lot of moving parts and uses a lot of different libraries. It's a huge step up from what you're currently working with in Brave&True.

1πŸ‘
Scott Meyers 2021-01-12T22:31:41.073700Z

When I evaluate a line referencing a function, after changes were made to that function, those changes aren't being reflected when evaluating the line. Evaluating that function and then evaluating the line referencing it shows the changes. Why is that?

dpsutton 2021-01-12T22:33:30.074Z

can you be a bit more specific what "changes were made to that function" means?

Scott Meyers 2021-01-12T22:39:32.074100Z

Yeah, so say I have a function that adds 2 to a provided number, then I realize it should be adding 3. I'll change that number to 3 inside of the function, evaluate a line referencing that function, and it'll still add 2.

Scott Meyers 2021-01-12T22:40:44.074500Z

But if I evaluate the function and then evaluate the reference, that change will be reflected.

dpsutton 2021-01-12T22:41:00.074700Z

right. you need to reevaluate the function

dpsutton 2021-01-12T22:41:28.074900Z

until you reevaluate it with 3, the function exists but with the value of 2.

Scott Meyers 2021-01-12T22:42:15.075100Z

Cool, thank you! Just taking some getting used to on my part.

seancorfield 2021-01-12T23:09:29.075300Z

If it helps: Clojure is always compiled, even in the REPL, and compilation happens as you evaluate each top-level form. It's a good practice to get into to instinctively "eval top-level block" after every change you make to any function.

seancorfield 2021-01-12T23:09:51.075500Z

Funnily enough, I just gave a talk to the London Clojurians about this very topic... recording to be available soon!

Scott Meyers 2021-01-12T23:10:53.075700Z

Awesome, that does help! I'll keep an eye out for the recording.