Fork me on GitHub
#beginners
<
2022-04-13
>
v3ga02:04:36

How would you go about executing multiple expressions when a case is true? When I wrap it in (do...) I get nothing. When I remove it it at least loads base.css

didibus02:04:29

Hum, do should work, but I'm confused about your nested case?

hiredman02:04:10

You are embedding this in some kind of dsl for expressing html as data

hiredman02:04:27

Do composes side effects

hiredman02:04:53

But does not turn 2 pieces of data into one piece of data

hiredman02:04:28

How you do that will depend on what the interpreter for the data structure you are building accepts

hiredman02:04:41

Likely just create a list

👍 1
v3ga03:04:53

I'm using hiccup.... using a list makes sense. Lets see.

v3ga03:04:09

@U0K064KQV me too lol. I have pages that have different styles to them so i'm using feeding in a map to tell what type of page is used and it includes the right stylesheet.

v3ga03:04:54

No dice... even (apply include-css ["css/base.css" "css/style.css"]) doesn't work. Alrighty, I'm going to take a different route. I've seen this work but the person was using rum.

hiredman03:04:12

No, just make a list

hiredman03:04:59

(list (include-css ...) (include-css ...))

hiredman03:04:13

https://github.com/weavejester/hiccup/blob/master/src/hiccup/page.clj#L83 and include-css from hiccup does indicate it would work with apply anyway

v3ga03:04:44

Did that as well... that should work. It may be something else.

hiredman03:04:02

Is the include-css you are using that one?

v3ga03:04:27

yeah, i was looking at that and that gave me the idea to do (apply...) . Yup

hiredman03:04:22

It does work like that, so the fact that it doesn't for you means you have something else going on, how are you rendering the hiccup?

hiredman03:04:34

My guess is you aren't rendering it using the html function from the hiccup library, but something else, which doesn't know how to render seqs/lists (which hiccup does)

v3ga03:04:37

Thats what i'm thinking. And I've verified both stylesheets work before I started toying around with 'case'. Then 'case' does work because when I go to my 'vivarium' page it loads that stylesheet correctly.

hiredman03:04:16

Have you looked at the html that is being rendered?

hiredman03:04:27

How sure are you that what you are looking at corresponds to that code? Have you restarted your process to make sure it is running code that is on sync with what is on disk?

v3ga03:04:31

omg i'm sorry.... o_O

v3ga03:04:14

wtf,,,somehow I deleted my style.css

v3ga03:04:22

Ok, it is indeed working. I know exactly what I did.... I cut some code from style.css and put it in a register to move to a new namespace *using Garden' and completely forgot about it.

Godwin Ko06:04:05

When writing macro, can I invoke functions in dependency libraries other than those in clojure.core? Does the compiler environment the same for clj & cljs? :thinking_face:

didibus15:04:08

You can invoke Clojure and cljc functions, but not Clojurescript.

1
Sakib10:04:29

I'm learning Clojure for 2 weeks. I aim to build a web app with Clojure backend and a Clojurescript frontend. I see there are three Project configuration tools, Leiningen, Clojure CLI tools and Boot. Which tools should I use?

practicalli-johnny10:04:39

The web app code will be the same regardless of project tool. Leiningen is pretty self contained app with a few pluggins, using Clojure for the project configuration Clojure CLI is a collection of tools and configurations, using data (edn) to define a project (and Clojure if there is a need to define custom build tasks). Both are relatively easy to pick up, although Leiningen has fewer pieces. Boot didn't really get that wide an adoption in the community

practicalli-johnny10:04:36

There are some projects building web apps in one of my books https://practical.li/clojure-web-services/

practicalli-johnny10:04:33

https://luminusweb.com/ is a flexible template for creating full stack projects that can provide examples. There are lots of options to try, so suggest trying to keep it simple to start with

practicalli-johnny10:04:53

There is also https://kit-clj.github.io/docs/guestbook.html which is a newer project (I think from some of the same authors of Luminous)

dorab16:04:07

If you are following some tutorial or book, then use whatever tool that uses. If you are building your own project, I'd recommend learning and using the CLI tools.

1
bortexz13:04:16

In a macro like with-precision, can I dynamically pass the precission from a variable at runtime?

delaguardo14:04:27

You have to give a bit more information) can you share this macro?

bortexz18:04:48

It’s on clojure.core

bortexz18:04:45

It’s used as

(with-precision 10 <decimal ops...>)
but I’d like to have precision to be dynamic, wondering if there is any way to do it

noisesmith18:04:55

macros cannot use run-time data unless you call them at runtime (eval)

noisesmith18:04:13

and eval is usually a sign you are making a big mistake

noisesmith18:04:20

if you look at the macro itself, it shouldn't be hard to use the uglier expanded version with a runtime determined value

noisesmith18:04:57

(cmd)user=> (defn example [precision] (binding [*math-context* (java.math.MathContext. precision)] (/ 1M 3)))
#'user/example
(cmd)user=> (example 10)
0.3333333333M
(ins)user=> (example 2)
0.33M
user=>

bortexz20:04:04

yeah, so far I’ve been doing the binding of math context myself, wanted to make sure i wasn’t missing something on macro side. thanks!

Gunnar13:04:41

Is there any convention (naming) for functions that return functions? I feel like it would clarify my code, compared to functions that return another value type. In this particular case, I bind some predicate conditions using a closure and return a predicate with lower arity. But then using the question-mark convention seems off. It is not a predicate, but it returns a predicate.

Darin Douglass13:04:05

i tend to use -fn as a suffix

👍 1
☝️ 1
kennytilton17:04:25

I have seen -factory used in other contexts.

leifericf17:04:30

I like @U02EA2T7FEH’s -fn suffix. By the way, would this be a situation where specs or metadata and tooling could help as well?

noisesmith18:04:51

I think returning a function is normal and expected and doesn't need a naming convention

💡 1
Gunnar19:04:54

For what it's worth, I also think it is normal... But I still appreciate your opinion! 👍🙏

Gunnar22:04:36

• OK, so to conclude the original question, no one seems to be aware of any such convention. • I noticed that it is indeed often easy to see by the position where the function is invoked that it must return a function. (Like when used with map, filter and such higher order functions). No real need for a special name for that reason. • Let me explain that my original trigger was not so much understanding (reading) code that was already written and working, but rather while I was writing new code I noticed I liked making many very similar helper functions, differing only in parameter style (takes collection or &args / apply, etc.) and return value. Thus it became a challenge to name them well, and to know which variant to pick in each case. I know what type i need it to return (e.g. a predicate), but what was that one named again? • I think this has been remedied a little by improved style now. One strategy I use more now is to combine such similar functions under only one polymorphic function name, using multiple arities (& sometimes dispatching on the parameter-type). In such setups there are fewer function names to remember. It makes sense that this returns a function if the parameters are under-specified, but return values when parameters are fully specified. • I have noticed I have also improved in making small composable functions (that often return functions). Efficient composition makes the calling code compact enough without a nagging feeling that every usage variation needs to be factored out into its own helper functions. • I might possibly use -fn or -p or some such convention if I feel it helps in some particular case, and (no offense), I don't want to make more "factories" in programming anymore 😉

leifericf17:04:40

Tip for fellow beginners: Using Visual Studio Code with Calva, the command “https://calva.io/getting-started/#there-is-also-standalone-repl” is convenient as a scratchpad when exploring and trying things out, messing around with code examples from Clojure books, etc.

leifericf17:04:04

This is what my book-reading setup looks like.

seancorfield17:04:33

You can open a PDF directly inside VS Code so you can move it around just like another tab/panel. No need to have your editor and reader side-by-side.

leifericf18:04:29

Awesome! Thanks for the advice, @U04V70XH6! I have my PDF books in the “Books” app so that my highlights, notes, etc., sync automatically between iPad, iPhone, and macOS. Else I would have done that right now!

seancorfield18:04:19

Ah, I've switched away from macOS to Windows/WSL2 (after being a Mac user since the early '90s) but, yeah, having a cross-device sync'd PDF reader is a good reason to tile the editor and the reader 🙂

👍 1
leifericf18:04:21

Yeah, it’s pretty nifty! The only thing that sucks is that it doesn’t sync my read location, so I must manually remember and scroll to the right place when switching devices.

didibus18:04:15

You can do the same in Cider (Emacs). If you open an empty buffer and just jack-in, it'll connect you to a default REPL with only your deps from your user deps.edn

leifericf18:04:53

Oh, interesting… I just tried this:

(= 'something (quote something)) ;; => true
And learned that 'something is equivalent to (quote something).

hiredman18:04:03

Try ''something (just type it in your repl)

leifericf18:04:55

Huh! Would you look at that…

leifericf18:04:42

I went too far…

hiredman18:04:58

Is it actually more interesting in the standard repl

hiredman18:04:20

Whatever you are using is doing some pretty printing that is obscuring things

hiredman18:04:12

Also (read-string "'something")

leifericf18:04:17

Oh! How peculiar.

didibus18:04:20

It's all quite logical. First your source code is "read" by Clojure. When reading your source code, the text: 'something is translated into (quote something). We call that read-time, which is the set of translations Clojure applies when reading source code. Once you have (quote something), that is then evaluated as code, when that happens, quote is a special form that tells the compiler that what follows shouldn't be evaluated, but returned as unevaluated code. Thus evaluating (quote something) will return something. This all happens recursively, which is where the mind bending occurs. ''something is read as (quote (quote something)) And when you evaluate (quote (quote something)) the first quote tells Clojure not to evaluate the rest but return it as it is unevaluated, and so you get (quote something) back. Some printers will if you want "unread" things so you get them back in source code format in a way that they can be "read" back into the same thing, that's why you might see it printed back as: 'something

💡 1
didibus18:04:24

It takes a while for all this to sink in, but it's all based on a simple set of logical steps, but together they compose to produce results that can be a bit difficult to reason about at first.

👍 1
didibus18:04:00

Clojure has 3 translation steps normally:

<source code>
  -read-> <code>
    -macroexpanded-> <code> 
      -evaluated-> values

didibus18:04:00

read-string takes a string of <source code> and returns you the <code> for it as read by Clojure. So it lets you see what the read translation looks like after reading.

didibus18:04:33

This is a good read: https://clojure.org/reference/reader Even if you don't understand everything right away. I think it's good to read it. Later as you practice more Clojure you'll start to have that click and it's good to have it in your brain.

👀 1
hiredman18:04:12

Also (read-string "'something")