Fork me on GitHub
#beginners
<
2023-03-27
>
Vishva Nath Dutt Sharma11:03:36

Hey folks, I am trying to run a function mutiple time with different argument, I wrote the implementation like

(map (fn [x y] (and x (pos? y))) [true 1 2 4 5])
but it throws exception, I am not able to understand, why? can you please help?

Martin Půda11:03:34

(fn [x y] (and x (pos? y))) is function with two arguments, map expects function with one argument

Vishva Nath Dutt Sharma11:03:58

so in this case

(map pos? [1 2 3 4])
it should work, but this also sends NPE, bit puzzled with map

dgb2311:03:22

For me it evaluates like so:

user=> (map pos? [1 2 3 4])
(true true true true)

Vishva Nath Dutt Sharma11:03:29

something wrong with my compiler then 😨

dgb2311:03:26

Never seen that happening. maybe you redefiend something that you shouldn't have? I would just restart the repl

Vishva Nath Dutt Sharma11:03:53

Ah, I see. restarting helps

dgb2311:03:08

Also you might be looking for every? I think that's the function you want to use here

👀 2
dgb2311:03:02

Your original function looks a bit like you wanted to use reduce instead of map

dgb2311:03:34

Where you reduce over a collection and AND everything together. every? does that for you

Vishva Nath Dutt Sharma11:03:23

yes, every? is what i was looking for. thanks for guiding me. 🙏

🚀 2
Can12:03:37

Hello, how can I import another namespace into my current namespace? (I would like to use functions that I declared in another namespace)

delaguardo12:03:15

what is "current namespace" to you?

Can12:03:42

(ns study.VeriAnalizProblemleri.D01
this is my current namespace, this is my another namespace that I want to call functions

Can12:03:00

(ns study.reusable-functions)

Can12:03:45

my project structure

simongray12:03:50

(ns study.VeriAnalizProblemleri.D01
  (:require [study.reusable-functions :as rf]))

;; call a function using the alias
(rf/my-function x)

Can12:03:00

I tried something similar,

Can12:03:09

ah ok I understand, thank you so much

skylize21:03:59

You can also use the require function, but in that case the vector needs to be quoted.

(require '[study.reusable-functions :as rf])

Can12:03:07

(:require [namespace.users :as users] 

Madara Uchiha13:03:38

I have a vector and a function read-from-vec that reads some elements off of the vector, and returns the form [(elements read) (elements still in the vector)] - I'd like to produce a lazy seq that endlessly invokes read-from-vec until the second elements that returns is empty. I tried using lazy-seq but I can't wrap my head around how it works

Madara Uchiha13:03:40

(defn decode-all
  [byteseq]
  (let [[curr rest] (read-next-instruction byteseq)]
    (lazy-seq (cons curr (if (seq rest) (decode-all rest) nil)))))
Alright got it, although I don't like that if 😞

Jakub Šťastný15:03:55

Hey guys. 2 days ago I started to see how to convince spec to be reasonable and allow me to use variables. The problem was that if you give it (s/keys ::req vector-var), it'll fail screaming that vector-var is no vector. We discussed it here and one solution was to use eval:

(eval `(s/def ::cost-of-sale (s/keys :opt-un ~list)))
Which looked worth it, but turns out that eval increases the bundle size considerable (this is CLJS/ShadowCLJS), so that's a no-no for me. Alex M said spec2 solves these problems out of the box, but ... spec2 hasn't been ported to CLJS yet. So I'm trying to write a macro. I was surprised what an exercise it is to tell CLJS macros are OK, but whatever, got it working. Now I'm down to actually writing the macro definition and I got stuck. This is the code that uses the macro:
+  (def product-reqs [::name ::sales-price ::cost-of-sale])
+  (def product-opts [::intro-date ::disco-date ::seasonality])
+
+  (s/def ::product (macros/skeys :req-un [::name] :opt-un product-opts))
+  (s/def ::overrides (macros/skeys :opt-un (disj (conj product-reqs product-opts) ::name)))
+  (s/def ::complete-product (macros/skeys :req-un products-reqs :opt-un product-opts))
+  (s/def ::full-product (macros/skeys :req-un (concat product-reqs product-opts))) ; For specs, generate a product with everything, optional or not.
You can see what I'm trying to achieve here, right, I just don't want to keep updating a bunch of vectors (which I always forget to do). As far as the macro goes, I got here:
+  (defmacro skeys [& {:keys [req-un opt-un] :as forms}]
+    (prn :skeys `(s/keys :req-un ~req-un :opt-un ~opt-un))
+    `(s/keys :req-un ~req-un :opt-un ~opt-un))
But it's not expanding the variable. I thought that's what the backstroke for(?) So how do I replace the reference by its value, so s/keys is kept happy? Is it even possible what I'm trying to do? I do have that vector available at compile time, so I assume there should be a way to feed it into s/keys as such.

kennytilton15:03:26

This may be my fault. After we joked about writing a macro to solve the evaluation problem, I paused to contemplate what that would look like, and realized, oops, still cannot get past the symbol. I should have followed up with a warning. Mea culpa.

Jakub Šťastný15:03:48

No worries @U0PUGPSFR, I thought exactly the same. Being used to eval with a string (which definitely still shapes how I conceptualise these things), it would have worked (`eval "s/keys :req-un #{req-un.inspect} :opt-un #{opt-un.inspect}"` would be the Ruby equivalent, inspect is like pr-str). But yeah, can't get past the pesky ref 🙈

Jakub Šťastný15:03:08

Never mind, at least I learnt how to do macros in CLJS.

seancorfield15:03:15

Just to clarify: you do not have the "vector available at compile time" -- product-reqs and product-opts don't actually get their values until runtime, after the macro has been expanded.

seancorfield15:03:29

When macros are expanded, you only have code -- symbolic expressions. Code is not running at that point, so there are no values.

Jakub Šťastný17:03:31

Thanks for the clarification @U04V70XH6.

Jakub Šťastný17:03:29

That's actually very useful to know, I always worked with languages that do everything at runtime (Ruby/JS), so I'm a bit lost in what's compile time and what isn't.

seancorfield17:03:26

With Clojure, the important parts are "read" and "eval". Macros are expanded as part of "read" -- after turning text into symbols (well, into symbolic expressions). Code is compiled as part of "eval" (it wouldn't really matter if compilation -- from symbolic expressions to JVM bytecode or to JS in CLJS -- didn't happen and Clojure was interpreted, except for speed, although some hosted interop depends on "compilation"). Until the "eval" part starts, there is no "runtime" and therefore no "values" -- only symbols/symbolic expressions. What makes Lisps unique is that macros are written in the language itself and they "run" in the "read" phase, taking symbolic expressions as input and producing symbolic expressions as output. What makes it confusing is that macros are "evaluated" and have the full capability of the language available to them, but they live in a world of symbols rather than values, so they get data structures passed in and can manipulate those data structures however they want, and produce new data structures -- they can perform explicit lookups or evaluations but you have to think carefully about the context they run in (previous forms will have been read and evaluated but you have to know how to address the state that creates):

build=> (def foo 42)
#'build/foo
build=> (defmacro bar [x] (println (deref (get (ns-publics *ns*) x))) `(+ ~x ~x))
#'build/bar
build=> (bar foo)
42
84
build=>
(and using *ns* is fraught, because of how it is bound -- it happens to work in this context)

Can17:03:58

Hello, I have some easy tasks to study and learn Clojure. I solved my first task but wondering that is there any easier way to do that?

;Input:     <--------
;
;
clojure ;[{:name "ali" :surname "veli"} ; {:name "batu" :surname "can"}] ;
;
;Output:    <-------
;task 1     <---
;
clojure ; [["ali" "veli"] ; ["batu" "can"]] ;task 2 <--- ;
clojure
;["aliveli" "batucan"]
;
(def my-vec [{:name "ali" :surname "veli"} {:name "batu" :surname "can"}]) (rf/transform-outer-coll-to-vector (rf/flatten-one-level (for [lenght (range 0 (count my-vec))] (update [] 0 #(str (into [] (vals (get my-vec lenght))) %))))) ;task 1 <--- ;==> [["ali" "veli"] ["batu" "can"]]
(defn flatten-one-level [coll] (mapcat #(if (sequential? %) % [%]) coll))
(defn transform-outer-coll-to-vector [coll] (apply vector coll) )```

pppaul17:03:49

the code you posted doesn't do what the comments suggest.

pppaul17:03:55

;; => ["[\"ali\" \"veli\"]" "[\"batu\" \"can\"]"] that is the output i get from running your code.

pppaul17:03:20

also, you seem to be re-implementing core functions of clojure, is this your intention?

seancorfield17:03:55

Probably the easiest way to do the transform you say you want is with map and juxt:

(def my-vec [{:name "ali" :surname "veli"}
             {:name "batu" :surname "can"}])
#'user/my-vec
user=> (map (juxt :name :surname) my-vec)
(["ali" "veli"] ["batu" "can"])
user=>

seancorfield17:03:55

But that involves quite few "steps" in how you think about problems.

seancorfield17:03:15

(if you really want a vector output instead of a sequence, use mapv instead of map there)

pppaul17:03:39

(->> coll (mapv (comp vec vals))) should work as well, but the juxt version is better if you want to be more declarative

seancorfield17:03:11

The first observation is that you want to apply a transformation to each element of your original data -- that leads you to map (or mapv). Then you look at the transformation your want to apply: taking a hash map, extracting the values associated with some of its keys, and producing a vector of those values. So you want {:name "ali" :surname "veli"} => ["ali" "veli"] which you can get several ways. The most straightforward would be [(:name data) (:surname data)] So you want (mapv (fn [data] [(:name data) (:surname data)]) my-vec) for a straightforward approach.

seancorfield17:03:09

Then you can look at ways of simplifying (fn [data] [(:name data) (:surname data)])

dpsutton18:03:27

I’d also ask if you post this much code to use the code snippet so it’s collapsible. Always happy to have lots of code to talk through and help, but not taking up so much space is helpful for others

stantheman18:03:57

Yes Can if you are a Slack green-horn like I was to insert code click + icon on bottom left, then in txt snippet window dropdown to recognise Clojure code. Cut and paste code in that window...

Can19:03:14

Before everything, thank you so much to everyone who helped me, I wasn't close to the computer so that's why I wasn't able to respond to your messages. @U0LAJQLQ1 I don't want to copy core Clojure functions, I want to reach my goal and while doing that learn Clojure step by step. @U04V70XH6 Thank you for separating your time and clear explanation. @U11BV7MTK and @U03RA7KLH7C I checked that + button at the bottom left side, but I wasn't sure how to do that. I want to create clear and readable codes for everyone. Is there any demo about this usage? Or any detailed explanation about how to post codes, etc.

dpsutton19:03:35

If you don’t see it, search for “snippet” in the “search shortcuts” option. I think there’s also a keyboard shortcut that i’ll look up for you

dpsutton19:03:58

I see it in the list:

dpsutton19:03:25

yeah perfect

Can19:03:33

Should I copy codes in content box, if needed I should write my messages into text input. right? 🙂

dpsutton19:03:19

don’t worry about it. Your text is very short. the code takes up quite a few lines. The snippets are collapsible. It’s just trying to make sure big blocks don’t hog the main channel. But no worries and carry on as you are 🙂

2
Can19:03:53

hello 🙂

Can19:03:12

Is it okay?

dpsutton19:03:04

that’s perfect. And again, it’s really just for when the code blocks get lone. for two lines of code don’t worry about it

2
Clojuri0an21:03:34

Am I thinking of this wrong? I have something like this

(def client-secret (fetch-client-secret))
(defn fetch-client-secret [] ...)
I feel like I'm thinking of this wrong / in a different language. Also I can't group my def at the top with my other related defs, it has to be called below defn

seancorfield21:03:58

Clojure reads and compiles each form in order as each file is processed. That means you have to have at least a declaration of a name available before you can use it.

seancorfield21:03:34

You can either (declare fetch-client-secret) or put the def of client-secret after the defn of fetch-client.

seancorfield21:03:04

declare isn't widely used -- Clojurians get used to having the top-level functions at the end of a namespace.

dpsutton21:03:11

I’m not sure declare helps in this instance though right?

escherize21:03:30

I’d argue clojure code tends to be easier read as a consequence of this single-pass behavior, too

dpsutton21:03:35

the def has to happen immediately. Clojure doesn’t register that it needs to come back and satisfy this def

2
seancorfield21:03:21

Right, not in this case because the def needs the value. Having side-effects in def is considered a bad idea -- because that code executes whenever the namespace is loaded.

👍 2
escherize21:03:27

alternatively

(def client-secret ...)

seancorfield21:03:34

(def client-secret (delay (fetch-client-secret)))
...
@client-secret ;; (fetch-client-secret) will be called here at the first deref of client-secret

Clojuri0an21:03:51

@U04V70XH6 I understand now why this has to be the case, but I guess what I'm wondering is what the pattern / style is supposed to be for defining grouped global variables when a variable depends upon a function that has to be called. Normally, I try to separate the functions and the variables and have the global variables at the top

seancorfield21:03:29

def expressions -- what you're thinking of as "global variables" -- should not be calling (side-effecting) functions, in general.

2
seancorfield22:03:25

As a general guideline, we try to avoid "global variables" except for giving names to what would otherwise be "magic constants", and we try to write our code to work on the arguments passed into them instead. That makes code easier to understand and easier to refactor (and easier to test).

Clojuri0an22:03:48

How should I reconsider what I'm trying to accomplish? My goal is to have a symbol(?) that I can take a key from, it pulls the key from an api

Clojuri0an22:03:09

Should I just call the defn?

seancorfield22:03:10

Presumably, you have code that uses client-secret in multiple places or multiple times?

seancorfield22:03:03

Perhaps think about your -main function doing some initialization -- calling (fetch-client-secret) when it starts up, and passing the result of that into your code that needs the client secret value?

👍 2
plus_one 2
Clojuri0an22:03:31

In the future yes, it should be called multiple times. Only once for now. I don't have a -main function, the (cljs) program is running from init and ^:dev/after-load start[] -- should I have -main defined?

seancorfield22:03:23

Oh, ClojureScript.

seancorfield22:03:56

Well, wherever your application is doing it's initialization is where you'd call this I guess.

seancorfield22:03:28

-main is the entry point for Clojure programs... but ClojureScript is going to depend on what tooling you're using I suspect...

seancorfield22:03:48

I don't know what ^:dev/after-load is...

Clojuri0an22:03:39

I'm not sure if it's shadow-cljs specific, but iirc it's the programs ran after re-saving the main.cljs file is saved (without having to refresh browser page)

seancorfield22:03:29

Are you in the #C6N245JGG channel? They might be able to suggest some good patterns for initializing stuff like this and making it available to your "program"...

Clojuri0an23:03:49

Yes, I'll give it a try. Thanks @U04V70XH6

Clojuri0an21:03:48

Where do I look in the style guide to learn to format a vector(?) like

[[:form {:on-submit (payment)}
    [stripe-card-input-section]
    [:button {:style "button-basic"}
              "Confirm order"]]

seancorfield21:03:47

https://guide.clojure.style/ is the style guide most folks use -- but, in general, most Clojure-enabled editors should indent/format code for you... what editor are you using?

seancorfield21:03:55

If I paste that code into my editor, I get this:

[[:form {:on-submit (payment)}
  [stripe-card-input-section]
  [:button {:style "button-basic"}
   "Confirm order"]]]

Clojuri0an21:03:39

I'm looking there but not sure what section to look for. I'm using emacs, but I've experienced difficulties getting auto-indentation to work the way I like (in general), and prefer to manually indent code

Clojuri0an21:03:35

I think your formatting makes sense, I want to vertically align confirm order to the style map(?) though as

[:form {:on-submit (payment)}
    [stripe-card-input-section]
    [:button {:style "button-basic"};; add disabled
            "Confirm order"]]))

seancorfield21:03:49

You may well need to get used to "different" formatting than you're used to -- what you just posted is not idiomatic really.

seancorfield21:03:22

Let Emacs format your code and get used to it 🙂

Clojuri0an22:03:15

I'll see if I can get it to work correctly this time, what kept happening is every time I pressed enter it would indent my code a comical amount. I think it was a bug in my config

seancorfield22:03:51

Were you using Emacs before you started learning Clojure?

Clojuri0an22:03:45

I've had the issue with a few languages, I think my indentation is borked for some reason or I don't know how to configure it properly

seancorfield22:03:01

There's an #C099W16KZ channel which might be able to help you get that sorted out (or #C01GE5PD249 or #C09C8GRLY if you're using those variants).

seancorfield22:03:44

I used Emacs on and off for the best part of 30 years but finally switched to Atom and then VS Code and I'm really liking that setup now (since I can script it via ClojureScript using the Joyride project, by the creator of Calva which is the main Clojure extension for VS Code) -- but I know a lot of folks still love Emacs!

Clojuri0an22:03:06

I'll post there if I encounter any roadblocks. I like emacs because I can use it as my window manager, it keeps things very clean and minimal. But it is annoying when the cruft builds up

2
skylize21:03:51

> what kept happening is every time I pressed enter it would indent my code a comical amount. > > Quite possible that you just weren't used to Clojure style yet. Since we indent based on structure instead of by counting chars, it can lead to some pretty ridiculous indentation if you don't adjust for it with well-placed newlines.

(defn foo-bar-baz [value-a value-b value-c] [value-a
                                             "way-the-fk-out-here
                                             value-b
                                             value-c])