Fork me on GitHub
#beginners
<
2022-12-22
>
Apple06:12:43

is there a local version of eval that does not pollute the global ns?

delaguardo09:12:04

not in the core. but probably you can use https://github.com/babashka/SCI to get some isolation

rolt09:12:37

(defn isolated-eval [form]
  (let [tmp-ns (gensym)]
    (create-ns tmp-ns)
    (try (binding [*ns* (the-ns tmp-ns)] (eval form))
         (finally (remove-ns tmp-ns)))))

(isolated-eval '(def a))
;; => #'G__92156/a
of course it can still leak if you do ns manipulation in your form

dumrat08:12:58

I've read it somewhere (Don't remember where and don't remember the exact quote) that Clojure is a language of data (manipulation?) and this seems a really good way of putting what Clojure helps to do. So, instead of thinking of it as another programming language, this is a different way. I can think of some other "languages of data" (sql, excel ...). Is there any writing on this topic? Any other languages you can think of?

delaguardo09:12:03

sounds like the quote refer to clojure homoiconicity - https://practical.li/clojure/thinking-functionally/homoiconicity.html SQL and excel are declarative languages, Clojure is not. so it would be hard to compare them

👍 1
practicalli-johnny09:12:36

Yes, homoiconicity of Clojure means you write code that is a data structure (function definitions are lists) Data is also defined as a data structure (vectors, hash-maps, sets, etc.) As the code is a data structure and the data is a data structure then many/most/all of the clojure.core functions are for manipulating and transforming data structures. So it's very effective to take a data centric approach with Clojure, as there are so many functions to support that This also leads to community libraries and tools taking a more data centric approach, to the point where data is used to declaratively define aspects of a system, e.g. • Clojure CLI deps.edn configuration • Integrant resources/config.edn • Hiccup • Reagent - using a data structure to represent state I am sure there are many more examples. I think of Clojure as very much a general purpose programming language that predominantly encourages a data centric approach (rather than Object centric). I assume other Lisp dialects 'could' take this data centric approach but do not know enough to comment specifically.

👍 1
dumrat10:12:40

I don't think the quote referred to homoiconicity and I don't understand it that way. Clojure has a few different types of easy-to-use collections (list, vector, map, set). It has some abstractions on these collections (seq) and it has an extensive collection of data manipulation functions in core. Though, you can do a whole lot with even simply map, filter and reduce on Clojure collections) I wonder if there are other languages which let you do data manipulations so easily and naturally.

Ed10:12:19

I think I recall hearing about a book on this subject. https://www.manning.com/books/data-oriented-programming I've not read it, but I suspect it might relate to what you're talking about.

👍 1
dumrat10:12:20

@U0P0TMEFJ I've read this. But this book basically read like an attempt to introduce some concepts popular (or even taken for granted) in the Clojure world to the wider world. It uses js to teach stuff. It's a good book and gave some practical pointers on somewhat emulating Clojure in other languages. What I was thinking about was simply about data manipulation. I don't know if you can trump Clojure for pure data manipulation. I did some project Euler problems in Clojure sometime back and realized that almost all of the problems can be solved as data manipulation problems and most of the solutions had the same structure (data manipulation pipelines). And Clojure core functions are all you need for this. (here: https://github.com/nakiya/euler/blob/master/euler.clj). And it feels like at times that you are working with a language of data. Perhaps I'm not expressing myself properly and apologize if so.

Ed12:12:20

Well, data manipulation is basically what all programming languages do, and people adopted things like OO to add some structure to the data and transformations under the assumption that this would make maintenance easier as codebases grew, right? I think that there were some negative consequences to that decision that weren't really taken seriously by the wider development community until Rich Hickey's talks became popular. I think Clojure's success has come from making immutability the default and questioning a lot of the wisdom adopted by the mainstream programming culture, and I think that the dust hasn't settled yet. Languages like Perl and Javascript have hashmaps and arrays front and centre as primary data structures with objects more of and afterthought but built everything on mutable objects. I think the realisation that actually immutability by default solves a lot of the problems that people thought more rigid structure would solve without a substantial performance impact, and we can just throw away a lot of the complexity of OO-style languages is what makes it seem so profound.

👍 2
Muhammad Hamza Chippa08:12:33

Is it possible to render the hiccups component inside of promise body ?

(-> (promise) (.then (fn [value]
                       [:div value]
                       )))

simongray12:12:29

Assuming you're using reagent and what you're looking for is reactivity... Instead of trying to render inside the body of the promise, swap the value of an atom. Then make a reagent component that derefs that atom and it will render according to the value that came via the promise. (def val (r/atom nil)) (defn my-comp [] [:div @val]) And inside your promise you should call (reset! val value)

🙌 1
Itay Dreyfus08:12:29

Say I’ve got this map:

(def coffee-shops {:item-1 {:title "Cafelix"
                            :location "Tel Aviv"
                            :img ""
                            :ig ""
                            :level 5}
                   
                   :item-2 {:title "Cafetish"
                            :location "Tel Aviv"
                            :img ""
                            :ig ""
                            :level 3}
                   :item-3 {:title "HOC"
                            :img ""
                            :ig ""
                            :location "Tel Aviv"
                            :level 8}})
How can I loop over each one and extract only the :level value from each nested map? I guess I need to iterate over each one and extract the value but I’m struggling with it…

tomd08:12:51

like this?

(update-vals coffee-shops :level)
;; => {:item-1 5, :item-2 3, :item-3 8}

😮 1
👍 4
dumrat09:12:47

You can do a simple map on this: (code not tested) (map (fn [[k v]] (:level v)) coffee-shops)

✌️ 1
👍 1
dumrat09:12:49

or, (map :level (vals coffee-shops))

👍 3
Itay Dreyfus10:12:46

Amazing, thanks!

Michaël Salihi13:12:12

Another solution using comp: (map (comp :level val) coffee-shops)

👍 2
Frank Henard15:12:17

variation of dumrat's

(->> (vals coffee-shops)
     (map :level))

👍 1
Ho0man12:12:34

Hi everyone, This snippet returns false and when insepcting with spec/explain it shows that the data is not matched by the second spec in the spec/and with the following error :

;; Spec Definition
(spec/def ::FASF (spec/and (spec/or :A (spec/tuple any? even? any?)
                                    :B (spec/tuple any? odd? any?))
                           (spec/tuple any? any? any?)))
;; Fail
(spec/valid? ::FASF [1 2 3])

;; The result of `spec/explain-data` : 
#:clojure.spec.alpha{:problems [{:path [], :pred (clojure.core/= (clojure.core/count %) 3), :val [:A [1 2 3]], :via [:hermes.van-buren.sle-router.commons.state-machine.order.by-tag/FASF], :in []}], :spec :hermes.van-buren.sle-router.commons.state-machine.order.by-tag/FASF, :value [1 2 3]}
Why are the :A and :B suddenly part of the data? or am I using the spec/or incorrectly ? Both alt and or seem to return the key-val and cause the problem what else can I use here? Thanks

delaguardo12:12:34

[:A [1 2 3]] is the result of or validation, then it is passed to the next form for and which is (tuple ...)

Ho0man12:12:43

Hi, @U04V4KLKC yeah i figured but this reduces the reusability of specs

Ho0man12:12:21

so when I want to combine these two I have to write another spec that is aware of its context (that it is used after an spec/or )

delaguardo12:12:22

btw, and is unnecessary in that case

Ho0man12:12:57

Yeah the example is trivial ... just to show my problem

Ho0man12:12:41

Isn't that an anti-pattern ? is there a reason it is designed this way ? or I must refrain from combining specs that way ?

delaguardo12:12:13

I don't know why or was designed that way https://ask.clojure.org/index.php/8759/spec-with-nested-or-fails-unexceptedly here is a relevant question

Alex Miller (Clojure team)13:12:46

You can use the (undocumented) s/nonconforming spec wrapped around the s/or to not get conforming there

🙏 1
Alex Miller (Clojure team)13:12:36

I expect we will eventually have an option for that in s/or or in conform or somewhere

Alex Miller (Clojure team)13:12:23

Re why - specs with alternatives tell you which was matched in the conformed output

Ho0man14:12:52

@U064X3EF3 Great Thanks, Alexx

dumrat12:12:46

So I was trying something stupid:

(defn launch-portal []
  (require '[portal.api :as p])
  (def p (p/open))
  (def p (p/open {:launcher :vs-code})))
=>
; Syntax error compiling at (src/sudoku/core.clj:6:10).
; No such namespace: p
I understand the reason for the error but suppose I am stubborn and want everything portal inside the function and not polluting my top level?

Ed12:12:21

I think you're looking for requiring-resolve

(let [my-rename-keys (requiring-resolve 'clojure.set/rename-keys)]
    (my-rename-keys {:a 1} {:a :b})) ;; => {:b 1}

clapping 1
👍 1
dumrat13:12:03

That works!

👍 1
Robin Singh14:12:50

(defn nth-ele
  [eles idx]
  (if (= idx 0)
    (first eles)
    (let [[head & tail] eles]
      (nth-ele tail (dec idx))))
  )

(nth-ele '(1 2 3 4 5 6) 2)
How can I write this function better because It works but I've written it badly. I also don't want to use "first" but return that head variable but I can't access it above.

tomd14:12:29

I think the best way to write this fn is

nth
but if you really want to do it recursively like this, I think your solution is more or less ok. Maybe this is better:
(defn nth-ele
  [eles idx]
  (if (zero? idx)
    (first eles)
    (recur (rest eles) (dec idx))))

👍 3
Robin Singh14:12:06

I would use nth any day but I'm following an online exercise to learn clojure. Thanks your code looks super clean I was looking for the same.

🙂 1
dumrat14:12:46

You can use a reduce too if you want:

(defn nth-ele
  [els idx]
  (reduce (fn [i e] 
            (if (= i idx) 
              (reduced e) 
              (inc i))) 
          0 els))

👍 1
Robin Singh14:12:24

That's also a good approach. thanks

Ed15:12:05

You could also drop the first idx elements and get the first one?

(defn nth-ele [eles idx]
    (->> eles
         (drop idx)
         first))

  (nth-ele '(1 2 3 4 5 6) 2)

👍 1
Ed15:12:08

Or you could convert it to a vector and rely on the fact that vectors can be called as functions to look up their indexes?

(defn nth-ele [eles idx]
    ((vec eles) idx))

Sudip17:12:56

I have been trying to run these (https://github.com/steffan-westcott/clj-otel/blob/master/examples/manual-instrument/interceptor/average-service/src/example/manual_instrument/interceptor/average_service.clj) examples for hours, but have made little progress and it seems am missing out on something trivial. It's a simple jetty server, that calls another service to get sum of numbers and then calculates averages (the math involved is not important). Its doc (https://github.com/steffan-westcott/clj-otel/blob/master/doc/examples.adoc#pedestal-interceptor-example-1) says Start first REPL with chosen aliases and then In the second REPL, load namespace example.manual-instrument.interceptor.average-service. I start the REPL and then do (ns example.manual-instrument.interceptor.average-service), which seems to start jetty server (i grep for jetty in ps), but then the service works and localhost:8080 never responds. Being 3 days old to clojure, I have quickly run out ideas on how to debug. Any ideas on what might going wrong? Am i loading the repl incorrectly? *ns* does return the correct ns.

dpsutton17:12:40

you are creating an empty ns example.manual-instrument.interceptor.average-service. Instead, require it

dpsutton17:12:02

can you tell me what aliases are required to run this?

Sudip17:12:19

Sorry if I continue to do stupid stuff, but it gives

(require example.manual-instrument.interceptor.sum-service)
Syntax error (ClassNotFoundException) compiling at (/private/var/folders/rk/5c13s0ms2x5clpj31d6rstyr0000gp/T/form-init6291846887219197046.clj:1:1).
example.manual-instrument.interceptor.sum-service

dpsutton17:12:45

(require 'example.manual-instrument.interceptor.sum-service)

Sudip17:12:25

I don't think the aliases matter much, because they decide a bunch of things for opentelemetry and it's ok if that doesn't work (for the time being).

dpsutton17:12:41

without the dev alias it cannot load the namespace

dpsutton17:12:57

Error building classpath. Could not find artifact com.github.steffan-westcott:clj-otel-api:jar:0.1.6 in central (https://repo1.maven.org/maven2/)

dpsutton17:12:08

and once i add that i’m getting an error that it has no collectors

dpsutton17:12:43

clj -A:dev:otel:traces-collector-grpc

dpsutton17:12:01

and then i visit localhost:8080 and see “Not found”

dpsutton17:12:03

so i guess it’s close

dpsutton17:12:23

user=> [Clojure Connection repl 1] INFO org.eclipse.jetty.util.log - Logging initialized @33663ms to org.eclipse.jetty.util.log.Slf4jLog
[Clojure Connection repl 1] INFO org.eclipse.jetty.server.Server - jetty-9.4.44.v20210927; built: 2021-09-27T23:02:44.612Z; git: 8da83308eeca865e495e53ef315a249d63ba9332; jvm 17.0.1+12-LTS
[Clojure Connection repl 1] INFO org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.s.ServletContextHandler@36abc19f{/,null,AVAILABLE}
[Clojure Connection repl 1] INFO org.eclipse.jetty.server.AbstractConnector - Started ServerConnector@62733b34{HTTP/1.1, (http/1.1, h2c)}{localhost:8080}
[Clojure Connection repl 1] INFO org.eclipse.jetty.server.Server - Started @34082ms
[qtp983123995-26] INFO io.pedestal.http - {:msg "GET /", :line 80}
Dec 22, 2022 11:58:41 AM io.opentelemetry.sdk.internal.ThrottlingLogger doLog
SEVERE: Failed to export metrics. The request could not be executed. Full error message: Failed to connect to localhost/[0:0:0:0:0:0:0:1]:4317

dpsutton17:12:32

no idea what any of this does but the webserver is running and loaded

Sudip17:12:35

Error building classpath. Could not find artifact com.github.steffan-westcott:clj-otel-api:jar:0.1.6 in central () I think this link is broken, but i could get over it by building the codebase (but i don't expect help with that)

dpsutton17:12:52

in either case sounds like you are good then?

dpsutton18:12:18

not sure what it is looking for on port 4317 but its trying at least ¯\(ツ)

Sudip18:12:54

I am now getting FileNotFoundException. Now maybe some path is incorrect

sum-service git:(master) ✗ clj -A:dev:otel:traces-collector-grpc
rlwrap: warning: could not set locale
warnings can be silenced by the --no-warnings (-n) option
Clojure 1.11.1
user=> (require 'example/manual_instrument/interceptor/sum-service')
Execution error (FileNotFoundException) at user/eval1 (REPL:1).
Could not locate manual_instrument/interceptor/sum_service'__init.class, manual_instrument/interceptor/sum_service'.clj or manual_instrument/interceptor/sum_service'.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.

dpsutton18:12:23

you are not calling what i told you to call

dpsutton18:12:28

(require 'example.manual-instrument.interceptor.average-service)

dpsutton18:12:58

require takes a namespace name. not a filename (note the dots versus slashes)

dpsutton18:12:28

also no quote at the end. it is not a string

Sudip18:12:53

Ah, this is embarrassing. It did work. Sorry for asking trivial stuff. Thanks so much for the help.

dpsutton18:12:18

no embarrassment 🙂 it’s the beginners channel to help with exactly stuff like this

👍 1
Sudip18:12:36

I would have never noticed the extra quote thing.

dpsutton18:12:58

it stood out to me. and was in the error message. in a bit you’ll also notice it

dpsutton18:12:04

it’s just new to you at the moment

Sudip18:12:18

Yes, and coming from imperative languages a little non-intuitive. Desperate to get some work done. Hopefully, I'll find time during holidays to sit back and learn, rather than trying to hack around 🙂

dpsutton18:12:41

yeah you’re in a complicated area as a first project with Clojure

Sudip18:12:46

Indeed. But could finally get it to work. Thanks a lot @U11BV7MTK. BTW, since I do intend to learn it the right way (unlike Java, which I learned on the job), was planning to get a book. Is that the right way? If yes, any recommendations? I was thinking between the one by Alex Miller or Daniel Higginbotham. But any others that you might recommend or any other recommended way, in general?

lemuel18:12:59

Both of those books are great. I really value Russ Olsen’s ‘Getting Clojure’ as an introductory book to the language

practicalli-johnny18:12:27

There are some guides on sever-side development at https://practical.li/clojure-web-services/ you might find useful

Sudip18:12:37

@U017AGUF30R Super. I didn't know about this one. Will see around if I can find a copy. Thanks. @U05254DQM this looks awesome. Bookmarked. Will go through it in the coming days. Thanks.

practicalli-johnny19:12:12

There is more being added in the next few weeks...

Sudip11:12:45

Great. I look forward to it. Thanks @U05254DQM