Fork me on GitHub
#beginners
<
2021-05-05
>
Kenneth Gitere05:05:21

Hi guys! I'm still having a hard time fully understanding how to write Clojure macros. Are there any resources online for practising writing Clojure macros? I'm only learning about them so I don't have any examples of macros I've written incorrectly

dpsutton06:05:19

two resources: - clojure for the brave and true chapter on macros: https://www.braveclojure.com/writing-macros/ - http://grep.app search for (defmacro https://grep.app/search?q=%28defmacro&amp;filter[lang][0]=Clojure

👍 1
zackteo06:05:34

Hi everyone, I understand I can use reduce to do (reduce + [3 3 2]) => 8 But how do I use reduce to get (reduce + [[3 3][3 2][1 1]]) => [7 6] Do I do something with apply ? :thinking_face:

dpsutton06:05:36

(let [pairwise (fn [x y] (map + x y))]
          (reduce pairwise [0 0] [[3 3][3 2][1 1]]))

dpsutton06:05:34

pairwise addition is just adding first with first, second with second, and then reduce that over the collection of pairs

zackteo06:05:04

Sorry am a bit confused. If I want to extend it to 3. Should I do (apply map + [[3 3 3] [3 3 3] [2 1 3]]) then? Don't really understand how reduce pairwise works

zackteo06:05:52

okay i think i still need to understand how apply works in such cases :thinking_face:

dpsutton06:05:58

table=> (let [pairwise (fn [x y] (map + x y))]
          (reduce pairwise [0 0 0] [[3 3 3] [3 3 3] [2 1 3]]))
(8 7 9)
works just fine. it's because of the way map works. (map + [3 3 3] [2 2 2]) will be ((+ 3 2) (+ 3 2) (+ 3 2)) which is pairwise addition. pairwise means in a tuple, to add, add each "position" in one tuple with the same position in the other tuple

dpsutton06:05:20

i'm not sure apply really gets you anything in this problem of yours

zackteo06:05:34

whoops, I think i somehow skipped over evaluating that snippet, yeah that works

dpsutton06:05:26

if you really want apply you could do (map #(apply + %) (apply map vector [[3 3 3] [3 3 3] [2 1 3]])) The inner apply will pair up the first elements of all the tuples, then the second elements, and the first apply will add them all

zackteo06:05:27

apply does seem to work too (apply map + [[1 2 3 4] [1 2 3 4] [1 2 3 4]]) ;; => (3 6 9 12)

zackteo06:05:09

apply helps to get rid of the surrounding [] i guess

dpsutton06:05:11

oh right. of course. sorry about that. i got blinded away from that solution

zackteo06:05:41

no worries! thanks for your help 😄

Tim Robinson11:05:44

Hi, I'm using "lein repl" and trying to find out how to do things like history search etc. I've followed the trail from nRepl to https://github.com/trptcolin/reply which claims it has "history navigation and search and much much more" but doesn't contain any user guide. it mentions JLine but that doesn't seem to have a user guide either. can anyone point me at some documention to get me started?

flowthing11:05:55

I think lein repl uses readline if you have it installed, so history search specifically should be Ctrl+R. Obligatory "prefer evaluating things from your editor instead of typing into the REPL" caveat applies here, though. 🙂

Tim Robinson12:05:41

Thanks - the manual page for readline does include some user instructions so that's very useful. I guess a lot of this would be obvious to someone who doesn't use set -o vi in bash :-)

FHE12:05:02

So I'm trying to get started with shadow-cljs, and there seem to be 3 options for dependency management: shadow-cljs itself (using shadow-cljs.edn), leiningen (using project.clj), or deps.edn (tools.deps is something related but I don't understand it at this point).

FHE12:05:38

Is there a good argument for using any of the 3 options over the others? Actually I really don't want to add yet another tool, so Leiningen is probably out for me.

gon15:05:28

shadow-cljs is not for dependency management, it is for ClojureScript, lein and tools.deps are for dependency management

FHE00:05:57

Even though there's a shadow-cljs.edn file? OK. Thanks. I'll start with just that and maybe try moving to tools.deps (or is that deps.edn??) later.

FHE12:05:12

I'm guessing using shadow-cljs.edn will be a bit 'smoother', but using deps.edn will give me more well-rounded practice (since I would be using I would be able to use any future projects without shadow-cljs).

Ryan12:05:13

Hey all, still getting my feet wet and had a question about the most clojure-y way to approach something: I have a big map for various settings for authentication, e.g. endpoints, urls, token settings … when I’m actually using the map, I want there to be some sprucing e.g. combine the endpoint and url suffix into one field.. is the idiomatic way to do that to basically have the map, have a function that transforms the map, and always invoke the map by calling the function instead? Right now I just have the map, and the code that consumes it is very verbose e.g. :url (str (get-in map :auth :protocol) (get-in map :auth :baseURL) (get-in map :auth :urlPort) (get-in map :auth :urlSuffix)) Any clues would be appreciated 🙂

Tim Robinson12:05:41

as long as the map doesn't change, can't you pre-process it when you read it in (or whenever the namespace loads if it's hard-coded)? if you really need access to the 'raw' version as well, you could just expose both

1
👍 1
Ryan12:05:15

Thanks for the response, I don’t think I’d need access to the raw version, but we might want to change the map at some point via repl or other dynamic mechanism, but I suppose it would be as elementary as re-running the processing function now that you put it that way

Michael Stokley14:05:51

> is the idiomatic way to do that to basically have the map, have a function that transforms the map, and always invoke the map by calling the function instead? I think it's reasonable to transform data as it flows through a system to meet the needs of whatever component is making use of it - to basically have different data models for different regions of the code.

👍 1
Endre Bakken Stovner13:05:21

Does anyone know what https://gist.github.com/endrebak/7d238ad32472d94edd93b9deba9c3406 might be due to? They happen when I run lein shadow watch app on a luminus app created with +shadow. The code works on another machine, but when I tgzipped and copied the entire repo to a different machine these errors popped up. An example error is [:failed-to-compare "16.8.6" "16.9.0" ...]

> npm ls
[email protected] /Users/endrebakkenstovner/code/everclear
├── [email protected]
So I am pretty sure these errors are due to version mismatches, but I cannot see how to fix them. My package-lock.json:
1718-    "react-dom": {
1719:      "version": "16.8.6",
                     //^^^^^^^
1720:      "resolved": "",
Just remembered the project the errors come from is here btw: https://github.com/endrebak/everclear It is just a prototype under construction, so no point looking at the code.

Endre Bakken Stovner13:05:00

It seems like lein shadow watch app still works, but always complains about stale compilation output.

introom13:05:41

ns-resolve has an env param, what’s that for. (ns-resolve ns env sym)

Sebastian Ohlsson15:05:50

Hi guys rookie question here! Can someone give me an example of a next.jdbc transaction.

(defn main
  [budget]
(jdbc/with-transaction [tx ds]

                     
                       (for [b budget]
                         (sql/query tx ["
                        UPDATE hbi_bp.model_no_of_students
                        SET process_status_id = 'Locked'
                        WHERE calendar_id = ?
                        AND calendar_period_id = ?
                        AND organisation_pk = ?
                        AND version_id = ?
                        AND school_type_id = ?
                        AND program_id = ?
                        AND grade_year_id = ?"
                                        (:model_no_of_students/calendar_id b),
                                        (:model_no_of_students/calendar_period_id b),
                                        (:model_no_of_students/organisation_pk b),
                                        (:model_no_of_students/version_id b),
                                        (:model_no_of_students/school_type_id b),
                                        (:model_no_of_students/program_id b),
                                        (:model_no_of_students/grade_year_id b)]))
Im trying to go through an array of maps and update all those values that match without connecting to the db for each "for"-cycle. I can get it to work for the single case (a single row) but I cant go through an array. Any points would be awesome. Have a great evening.

ghadi15:05:06

for is a lazy sequence comprehension not a loop

ghadi15:05:30

need something to realize the sequence inside the with-transaction

👀 2
Sebastian Ohlsson15:05:26

I will look at it again with this. Thanks

Mark Wardle16:05:39

Hi all. Can I ask a style question please? I have a service that wraps two other services and provides a nice API. I have a deftype representing that unified facade and then in order to provide the implementation, I’ve added a protocol and implemented the methods for the type. But this feels wrong as I have no intention of providing multiple versions. So is it better to simply use the deftype as a way of holding some internal references and provide functions at a namespace level? I had thought it might be nice to provide Java interop in the future, but the reality is I’m more likely to write a proper Java wrapper and simply invoke functions anyway. TLDR; should I go through the contortions of defining a protocol simply to add implementation methods or is it fine to just use methods that take a handle of a (kinda opaque-ish) service implementation and forgo protocols completely?

alexmiller17:05:06

the cool thing about protocol functions is that from outside the namespace, you invoke them identically to how you'd invoke a non-protocol function

alexmiller17:05:08

so if you don't use a protocol, you can always start using one later in the implementation without breaking callers

alexmiller17:05:55

in general, it's usually better to make the API actual functions anyways (as then you have the opportunity to do custom logic there) and use a protocol for the SPI instead

👍 1
alexmiller17:05:53

we follow that pattern in the spec impl and it's been very useful

👍 1
didibus17:05:34

Doesn't sound like you need a deftype to me. Just use functions like so:

(defn make-service
  [other-service1 other-service2]
  {:other-service1 other-service1
   :other-service2 other-service2})

(defn some-api-for-it
  [service-map other-thing-you-might-need]
  ...)

(defn more-apis-for-it
  [service-map ...]
  ...)
And then a client does:
(def service-instance (service/make-service (FooService.) (BarService.)))
(service/some-api-for-it service-instance "12345")

Mark Wardle06:05:35

Thanks both. That’s really helpful. I will remove the protocol and make it as simple as possible for what I need now. I was getting itchy when i had to keep adding more methods to the protocol!

Ben Sless06:05:15

Another approach, especially when you need a single instance with no versions is to use reify. You can always reify into more protocols in the future.

Dave Suico16:05:21

Hi guys, I have to test a csv reader I made and I need to read a csv file that lives somewhere in the resource folder in my codebase. How can I traverse and locate my file? thanks!

Mark Wardle16:05:14

Hi. Have you seen http://clojure.java.io/resource https://clojuredocs.org/clojure.java.io/resource. As long as the other file is in your class path - you should be able to find it.

Dave Suico17:05:38

Hello there! Currently reading it now as you commented but I do not fully understand classpaths yet. Looking at the image, I think my sample file is separated from the classpath right?

Dave Suico17:05:31

altho I tried this and it works. Can I see a better call than this?

Mark Wardle17:05:22

It depends on your classpath. Which build tool are you using? You can include arbitrary directories in your classpath. The trouble with using an absolute filename is that it won’t work from a jar file - it works for your development environment only…. now I think some people use git and clj for production, but you’re better getting that path into the classpath, and using io/resource.

George Silva17:05:45

Hello friends! I'm pretty new to Clojure and I'm reading a few books and doing a few exercises. I have a few questions: 1. What are good resources in order to learn "design patterns" or more idiomatic code? 2. What is a good web "framework" (quoted because I do understand that frameworks are not really the clojure way) to get started? I tried several but they all seem a pretty complicated or have a pretty complicated boilerplate code (`lein new ...`). Any interesting resources for beginners that encompass API, database and maybe docker/docker-compose?

sb17:05:42

1) Clojure: The Essential Reference (meap) book > very good and helpful. Timothy Baldrigde Pivotshare video tuts (before this was on YouTube) similar good. Not exactly what you search, but I like both. Im not at laptop, maybe somebody can share better links to idiomatic code.

👍 1
tvirolai09:05:42

• The Clojure style guide (https://github.com/bbatsov/clojure-style-guide) is a good resource for idiomatic style. If you want to go deep into this, check out Zach Tellman's book Elements of Clojure (https://elementsofclojure.com/) • A good way to learn to write idiomatic code is to get feedback on your code. Try checking out the Clojure track (in mentored mode) on http://exercism.com • As to the framework thing, Luminus provides great configurable templates for getting your projects up and running: https://luminusweb.com/

Audrius17:05:39

Hello! how can we describe the map that is embedded in this defn body

(defn ok []
  {:pre  [(keyword? 6)]
   :post [(number? %)]}
  4)
It is also evaluated and assertions run. What else can go into that map?

delaguardo17:05:00

It is called "condition-map" in defn form

✔️ 1
alexmiller17:05:34

you can also see info in (doc defn) (as "prepost-map")

✔️ 1
alexmiller17:05:41

those are the only things that can go in it

✔️ 1
Audrius18:05:37

in (doc defn) documentation there is some attr-map? mentioned. I can not find a good explanation on what it is. What can it be?

alexmiller18:05:44

metadata map

alexmiller18:05:20

it's combined with the :meta

alexmiller18:05:20

it was included as an option at the end in case you have a large metadata map, you could put it after the main part of the function (using this is very unusual)

alexmiller18:05:28

most people don't even know that exists

😀 1
David Pham17:05:46

Hello everyone :) I am trying to use http-kit behind a proxy and the final endpoint is in https and the proxy is in http. When using babashka.curl/post with ˋ-x http://myprotoxy:my-port/%60 the request works, but it fails with org.http-kit.client. Same behavior with clj-http.client. Anyone would have a clue why that happens? [i am using Java 8]?

borkdude17:05:16

@neo2551 Did you enable the SNI client in httpkit?

borkdude17:05:46

and does it work with the (native) babashka httpkit client. rather than in Java 8?

David Pham17:05:51

Probably not.

borkdude17:05:56

(if so, then it's the SNI client problem)

David Pham17:05:57

Let me check with babashka.

David Pham17:05:04

Thanks for the help!

David Pham17:05:54

How would you configure it? Just require it?

David Pham17:05:13

Nope, it was not that xD

borkdude17:05:41

but does it work with bb then?

borkdude17:05:06

> but it fails with org.http-kit.client. Same behavior with clj-http.client oh, I see, then it's not http-kit specific

borkdude17:05:19

but still good to enable that SNI client

David Pham17:05:58

Thanks I will know for the future :)

David Pham17:05:15

I am just happy that you wrote curl because my colleague were showing the command by curl and I was a bit embarrassed to fail with httpkit. It also worked with python.requests (so I guess I could have used libpython-clj but in the worst case).

borkdude17:05:26

ooh it's a proxy

David Pham07:05:22

I think the issue is I am using basic authentication method with user:[email protected]

borkdude07:05:46

Maybe read the Java docs about it, I would have to look it up as well :)

David Pham07:05:34

So now, I can make it working with clj-http but not http-kit haha

borkdude07:05:13

why is that?

borkdude17:05:30

I missed that

borkdude17:05:37

you can set Java properties for this

borkdude17:05:21

e.g.:

java -Dhttp.proxyHost= -Dhttp.proxyPort=8080
see https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html This should also work with bb

borkdude17:05:43

with the clojure CLI it's -J-Dhttp.proxyHost= etc