Fork me on GitHub
#beginners
<
2022-09-12
>
Benjamin06:09:30

Hi, I'm looking for 'completely new to programing' guides for clojure. I made a website with a bb script and a fresh team member wants to hack on it

Dajana Herichova07:09:16

Hi, I started programming with Clojure as my first programming language, and I can suggest clojure for the brave and true book. Everything there is very nice and simply explained and full of jokes, so I really enjoyed working with this book :)

❤️ 4
👍 1
Benjamin07:09:12

ah yea totally that goes on the list

ChillPillzKillzBillz10:09:27

Hello All, I have a weird problem. I am trying out sicmutils.

(ns rand.filetry
  (:require
   [sicmutils.env :as e :include-macros true]
Deps entry:
sicmutils/sicmutils {:mvn/version "0.20.0"}
I have a macro as defined below:
(defmacro def-literal-function [label]
  (->> label
       (list 'symbol)
       (list 'e/literal-function)
       (list 'def (symbol label))))
When I run this macro it creates a literal-function defined in the global scope. e.g.
clj꞉rand.filetry꞉> 
(def-literal-function "theta")
#'demo.clerktry/theta
clj꞉rand.filetry꞉> 
(theta 't)
(theta t)
However if I need to run over a vector of labels e.g.
(def labels ["theta_1" "theta_2" "theta_3"])

(doseq [label labels]
  (def-literal-function label))
This doesn't work in the same way.... as
clj꞉rand.filetry꞉> 
theta_1
; Syntax error compiling at (..\Clojure\sicmutils-main\demo\.calva\output-window\output.calva-repl:0:0).
; Unable to resolve symbol: theta_1 in this context
What am I doing wrong? Why can't I access the values created by the macro?

pez10:09:24

What's the result and output of the doseq? You are using position_labels there, and not labels (which I think its your intention?)

ChillPillzKillzBillz10:09:24

yes that was a typo in my code. I've updated my code to fix this. It is not a typo issue in the original code. This is but an excerpt of the rest...

ChillPillzKillzBillz10:09:45

output of the doseq is just nil

pez10:09:36

Not an expert here at all, but I'm wondering... When you call (def-literal-function label), that would give the symbol label to your macro, right? So maybe you are just creating a literal function named label three times?

ChillPillzKillzBillz10:09:02

but when I am passing label to the def-literal-function it is a string. Not a function yet...

pez11:09:06

Yeah, I am not reading that code correctly. Let's wait for someone more macro-savvy to look at it. 😃

👍 1
seancorfield11:09:24

@U022LK3L4JJ You're trying to mix macro expansion and runtime values. You can see why it won't work with this simplified version:

user=> (def f "foo")
#'user/f
user=> (macroexpand '(def-literal-function f))
(def f (e/literal-function (symbol f)))
user=>

seancorfield11:09:15

As pez said, you're defining a literal function called label three times.

teodorlu11:09:41

As @U04V70XH6 suggests - use macroexpand to figure out if your macro does what you think it does! And when asking for help with a macro, including example input from (macroexpand '(your-macro your-args)) is very helpful. Is the output what you wanted? Not? Why not?

ChillPillzKillzBillz11:09:02

@U04V70XH6 I am a newbie... (still 😄) So I destructured labels into label in doseq. Here label is a string. I am passing a string to the macro. The only difference between calling the macro with the string directly and the non-working code is the doseq. How do I get around this problem? Any ideas?

seancorfield11:09:27

Macros are expanded first, so the argument is the symbol label. There are no runtime values at that point. Once the macro is expanded, then the doseq is evaluated. You are not passing a string to the macro, you are passing a symbol.

ChillPillzKillzBillz11:09:01

In my limited understanding I thought the whole point of macros is so that you can generate dynamic code to execute at runtime... so if I can't pass a string to macros, what is the right way of doing this?

seancorfield11:09:32

In real world Clojure, macros are not used much, and their execution model can be very confusing when you're learning Clojure.

1
seancorfield11:09:22

@U022LK3L4JJ If it helps at all, think of macros being "evaluated" (expanded) at compile-time and then the compiled code is executed (at runtime). The doseq, the binding to label, and the value of labels are all runtime things. They happen after your macro has been expanded. You could try to write a macro that you pass multiple (string) arguments that expands to multiple def expressions (wrapped in a do), so you could write (def-literal-functions "theta_1" "theta_2" "theta_3")

sp13:09:15

What would be a clean way of getting the nth element from index 0? For example

(func [0 1 2 3 4 5 6] 1)
#_=> [1 2 3 4 5 6]

(func [0 1 2 3 4 5 6] 2)
#_=> [2 4 6]

(func [0 1 2 3 4 5 6] 3)
#_=> [3 6]

pavlosmelissinos14:09:57

(->> coll (drop n) (take-nth n))
or as a function:
(defn drop-take-nth [n coll]
    (->> coll (drop n) (take-nth n)))
----- Examples:
(drop-take-nth 1 [0 1 2 3 4 5 6])
;;=> (1 2 3 4 5 6)

(drop-take-nth 2 [0 1 2 3 4 5 6])
;;=> (2 4 6)

(drop-take-nth 3 [0 1 2 3 4 5 6])
;;=> (3 6)

Epidiah Ravachol14:09:14

Perhaps (map [0 1 2 3 4 5 6] your-indices)?

Epidiah Ravachol14:09:31

I didn't either until I started pondering your question. So thank you for the opportunity to learn!

seancorfield14:09:20

In case you're wondering why that works, vectors implement IFn so they can be "invoked" with an argument, and they treat that argument as an index into themselves. Maps also implement IFn and when "invoked" with an argument, they look that argument up as a key in themselves (and return the associated value).

👍 2
seancorfield14:09:25

Also sets:

user=> (let [v [1 2 3]] (v 1))
2
user=> (let [m {:a 1 :b 2}] (m :a))
1
user=> (let [s #{:a :b}] (s :b))
:b
user=>

👍 1
sheluchin15:09:31

Are there any resources which summarize which exception classes to throw in which situations?

pavlosmelissinos15:09:56

I always throw ExceptionInfo (`ex-info`) and give the context as a map whenever I can. If you care about interop from Java it's probably more complicated than that though (and I honestly don't know).

sheluchin15:09:25

Hmm, no, I don't care about Java interop. Is that a common approach - to just throw ex-info like that?

pavlosmelissinos15:09:31

My impression is that it's quite ubiquitous 🙂 Not exactly a scientific experiment but a quick search on http://grep.app shows that throw (ex-info... is https://grep.app/search?q=throw%20%28ex-info&amp;filter[lang][0]=Clojure than https://grep.app/search?q=throw%20.%2AException&amp;regexp=true&amp;filter[lang][0]=Clojure That's roughly been my experience as well

gratitude-thank-you 1
sheluchin15:09:46

What a relief! I thought I was going to have to start committing the exception hierarchy bits to memory.

🙂 1
Ben Lieberman15:09:18

is there a way to use :keys to destructure a map without explicitly naming all the keys? I am reading over https://clojure.org/guides/destructuring and it gives multiple examples of the :keys shortcut but only with explicit bindings. I've seen the & args idiom used before in functions but that doesn't seem to work in my case. I've tried a couple variations and I either get nil or an exception nth is not supported on PersistentHashMap

dpsutton15:09:49

What do you want to accomplish? Destructuring’s whole point is to introduce an explicit binding based on the shape of the input data. If you don’t want a name introduced what do you want out of destructuring?

sheluchin15:09:39

You don't have to name all the keys. You just name whatever ones you need. Are you trying get explicit names for some keys and then have another binding for all the ones you didn't name?

Ben Lieberman15:09:08

But it seems like when I use :keys I have to match the actual key names exactly? That makes sense bc maps are unordered but if I just want keys by position should I not use a map?

dpsutton15:09:03

I’m not following. :keys is useful to destructure associative objects like maps. Where there is a key and a value. You can destructure by position just do that (which does not use keys)

dpsutton15:09:29

(let [[first-item second-item] [1 2]] (+ first-item second-item))

Ben Lieberman15:09:38

Yeah that's what I want @U11BV7MTK. sorry for the confusion

skylize16:09:42

You don't have to use :keys to destructure a map. It's just sugar for keeping the same name.

(let [m {:a 1 :b 2}]

  (let [{:keys [a b]} m]
    (println a b))       ;; => 1 2
  
  (let [{a :a b :b} m]
    (println a b))       ;; => 1 2

  (let [{c :a d :b} m]
    (println c d)))      ;; => 1 2
                         ;; => nil

☝️ 1
skylize16:09:32

Though, as you said yourself, you don't want to use a map if position matters.

seancorfield17:09:51

@U03QBKTVA0N Just be aware that if you try to use sequence destructuring on a hash map, there's no order to the key/value pairs, so "first" and "second" make no sense really.

didibus02:09:28

Also, a little confusingly, if you destructure a rest argument from var-args as a map, it treats it as a pair of key/values.

(defn foo [& {:keys [a b]}]
  [a b])
(foo :a 1 :b 2)
;;=> [1 2]
This applies to any sequence, so you can treat an ordered sequence as key/value pairs.
(let [{:keys [a b]} (seq [:a 1 :b 2])]
 [a b])
;;=> [1 2]
But this only works for sequences, not for vector for example, but it will for list or sequences.

2FO19:09:40

Hello, I'm getting this error.

(clojure.core/load "/min/src/min/core")
Execution error (FileNotFoundException) at user/eval6006 (REPL:1).
Could not locate min/src/min/core__init.class, min/src/min/core.clj or min/src/min/core.cljc on classpath.
when calling the following from the projects root directory in clj: user=> (require '[min.src.min.core] :verbose) Project structure
├── deps.edn
└── src
└── min
├── core.clj
└── db.clj

seancorfield19:09:20

If the file is src/min/core.clj then the namespace will be min.core -- src is one of the classpath roots and namespaces are relative to the classpath in terms of how they match filesystem paths.

seancorfield19:09:13

(assuming you are running clj in the folder containing deps.edn, which you should be @U01HBARPCFL)

🙏 1
2FO19:09:11

Thanks Sean, did the trick. I need to read up on classpaths and namespaces