Fork me on GitHub
#beginners
<
2021-01-05
>
Daniel Tobias04:01:15

Required namespace "react" never defined i am trying to build an application that is using reagent and i am getting this error. it is literally just the figwheel template for reagent

Daniel Tobias04:01:31

lein cljsbuild once min does not work at all, always results in depedency errors here

Daniel Tobias04:01:45

created the project with lein new figwheel appname -- --reagent

seancorfield05:01:47

@dan.yb.tobias When you run lein new figwheel appname -- --reagent, it says you need to run npm install -- did you do that?

Daniel Tobias05:01:56

Jan 04, 2021 9:02:27 PM com.google.javascript.jscomp.LoggerErrorManager printSummary
WARNING: 4 error(s), 0 warning(s)
ERROR: JSC_MISSING_MODULE_OR_PROVIDE. Required namespace "react" never defined. at /D:/Userfiles/Documents/Projects/Clojure/webpage/reagent-sample2/target/cljsbuild-compiler-1/reagent/core.js line 5 : 0
ERROR: JSC_MISSING_MODULE_OR_PROVIDE. Required namespace "react_dom" never defined. at /D:/Userfiles/Documents/Projects/Clojure/webpage/reagent-sample2/target/cljsbuild-compiler-1/reagent/dom.js line 5 : 0
ERROR: JSC_MISSING_MODULE_OR_PROVIDE. Required namespace "react" never defined. at /D:/Userfiles/Documents/Projects/Clojure/webpage/reagent-sample2/target/cljsbuild-compiler-1/reagent/impl/component.js line 6 : 0
ERROR: JSC_MISSING_MODULE_OR_PROVIDE. Required namespace "react" never defined. at /D:/Userfiles/Documents/Projects/Clojure/webpage/reagent-sample2/target/cljsbuild-compiler-1/reagent/impl/template.js 

seancorfield05:01:02

(which means you need npm itself installed)

Daniel Tobias05:01:57

ah somehow i missed it, ill give it a try ty

Daniel Tobias05:01:39

using lein new reagent-frontend reagent-sample +shadow-cljs to make the app works but i like the other one since it's easier to remember :^)

seancorfield05:01:02

I can repro your problem (but I don't have npm installed which is why I wanted to check you had run that step).

seancorfield05:01:26

I recently started playing with ClojureScript and I used the figwheel-main template, not the figwheel one.

seancorfield05:01:47

But then I'm using the Clojure CLI, not leiningen (except for helping beginners with lein 🙂 )

Daniel Tobias05:01:29

haha yeah I am trying to learn but i am constantly having issues

seancorfield05:01:44

I got the impression that figwheel-main had superseded plain ol' figwheel...

raspasov05:01:21

@seancorfield that’s definitely the case

Daniel Tobias05:01:45

so i should try the same thing but with figwheel-main ok

13tales05:01:29

Hey. I’m learning CLJS by working on a little project, and I have a question about a good and idiomatic approach to a fairly simple problem. For context, I mostly work as a JS/React dev. What I want to do: write a function that takes a collection, makes an HTTP request based on each value in the collection, and when they’re all complete, returns the results. I’ve done this before in JS; inside of a call to Promise.all, my code maps over the input array, uses await to wait for the HTTP response, and then does some simple operations based on the response and returns the resulting output. What’s a good way to do it in CLJS? I’m reading about core.async and find it comprehensible enough, but it’s a lot to absorb, and I’m curious how a proficient Clojure(script) developer would typically do this. 😅

13tales06:01:05

(Sure, I could use JS interop to use the promises that I’m familiar with, but that seems like it might defeat the point)

13tales06:01:18

I think the bit that I’m finding hardest to figure out is how to wait until all the requests have returned before returning the final output 😕

seancorfield06:01:15

@thomas.armstrong I'm just starting to (re-)learn cljs so I'll be interested to hear what people suggest. I'd be able to do this in Clojure on the JVM without having to think about it much, since multi-threading is so common, but cljs is an unknown for me...

13tales06:01:02

How would you do it with core.async in clojure? As I understand it so far, the main difference in CLJS is that only the (go ...) versions of the core.async functions are available, since the JS runtime is only ever single-threaded.

seancorfield06:01:17

I wouldn't use core.async for this in Clojure - I'd just use threads directly on the JVM, either via pmap (sledgehammer), future, or more likely an executor / thread pool -- depending on the likely size of the collection.

13tales06:01:38

Ah, gotcha. Sounds like a different world to JS 😄

seancorfield06:01:11

The JVM is very different. I've done almost zero JS stuff in my life. I've spent decades working on the JVM.

raspasov06:01:29

@thomas.armstrong I would use core.async for that, yes

13tales06:01:10

Mmm. I understand that core.async is pretty much a given, since javascript HTTP requests are asynchronous by nature. How would you wait for all HTTP requests to complete before returning the result?

raspasov06:01:39

(a/go
  ;initiate requests (replace (a/timeout... ) with a function that makes an HTTP request and returns a channel
  (let [resp-channel-1 (a/timeout (rand 1000))
        resp-channel-2 (a/timeout (rand 1000))
        ;wait for response
        resp-1         (a/<! resp-channel-1)
        resp-2         (a/<! resp-channel-2)]
   
    (println resp-1 resp-2)))

raspasov06:01:00

(:require [cljs.core.async :as a])

13tales06:01:20

Ohhh :thinking_face: You’d create a separate channel for each request? I’d been thinking more along the lines of creating a single channel, putting each response as it arrived, and then consuming from it .

raspasov06:01:49

One thing I’m gonna say though: even though this core.async “fun” 🙂 can get pretty elaborate, I’ve established over the years that it’s better to minimize the amount of concurrent HTTP requests you’re making (if possible); now, if you’re calling different services and not a service that you control, you might have no choice

seancorfield06:01:56

@U050KSS8M So, for a collection of URLs, you'd map over the collection to call async http fns that returned channels, then you'd map over the channels to take the values? Or use alts! over the collection of channels? (looping until you had all the values back?)

seancorfield06:01:30

(again, I guess it depends on how many HTTP requests you'd end up making?)

raspasov06:01:52

Unfortunately core.async doesn’t allow you to (map a-fn coll)

raspasov06:01:18

So some imperative-flavored looping can be involved…

raspasov06:01:58

Basically you can’t (map <! seq-of-channels)… you’re probably aware of that, it’s the same in Clojure

13tales06:01:16

> it’s better to minimize the amount of concurrent HTTP requests you’re making For sure. Unfortunately, the API I’m calling only accepts one parameter per request, and the number of requests will be small (< 20)

seancorfield06:01:36

But you can map a function over a collection that would produce a sequence of channels.

raspasov06:01:52

@thomas.armstrong right, so I just showed manually doing it over two channels,

raspasov06:01:15

So let’s see for many…

seancorfield06:01:38

You could map a blocking take over the channels 🙂 since you need to wait for them all to complete anyway.

seancorfield06:01:58

@thomas.armstrong What do you need to do with the HTTP results once you get them? Do you just want a collection of results or are you handing them off for further processing?

13tales06:01:03

@U050KSS8M Yeah, much appreciated; I can see how that would would work. I guess the thing I’m most curious about now, in terms of the approach that an experienced CLJS dev might take, is: why many channels instead of one channel? I’m new to the whole concept of channels, so still trying to build a mental model.

raspasov06:01:40

@seancorfield yes 🙂 that is a nice one in JVM Clojure

13tales06:01:18

@seancorfield Not much. A little extra processing per result, but just on the level of extracting some values from the response and then doing some simple arithmetic.

seancorfield06:01:31

@U050KSS8M Ah, there is no blocking take in cljs?

raspasov06:01:12

No (thread…), (<!!… etc

raspasov06:01:14

@thomas.armstrong there’s so many ways you can approach this; and to be fair, there’s no perfect solution, it depends on what you’re trying to achieve; you can have one long-lived channel that processes all requests; you can put channels on that channel and have one (go (loop []… (recur)) for the whole application that takes channels off the main channel, waits for a response and does something with it

raspasov06:01:07

channels on channels is pretty neat… I’ve used it; but if you can avoid having long-lived global channels, I’d prefer it; less “state” to manage

seancorfield06:01:51

Haha... this is why my cljs learning journey will be painful: I'm so used to a multi-threaded environment!

13tales06:01:10

@U050KSS8M > there’s so many ways you can approach this Yeah, that’s my dilemma. So much power, so little understanding (right now) of how to use it 😅

13tales06:01:43

Thanks for the responses. You’ve given me a starting point, I think.

raspasov06:01:28

(comment
  ;This takes at most ~2000 ms to execute
  (let [process-seq-of-channels
        (fn [chans]
          (a/go
            (loop [chans chans]
              (if-not (empty? chans)
                (let [ch   (first chans)
                      resp (a/<! ch)]
                  (println resp)
                  (recur (rest chans)))
                (println :done)))))

        fake-http!
        (fn [req idx]
          (let [resp-ch (a/chan 1)]
            ;TODO Do HTTP request!!!
            (a/go
              (a/<! (a/timeout (rand-int 2000)))
              (a/put! resp-ch {:resp req :idx idx}))
            ;TODO end
            ;return channel
            resp-ch))]
    (a/go
      ;initiate requests, replace fake-http! with a function that makes an HTTP request and returns a channel
      ;MUST use (doall...) to send the requests right away!
      (let [resp-chans (doall (map fake-http! (repeat 10 {:req 1}) (range 10)))]
        (println :starting)
        (process-seq-of-channels resp-chans)))))

raspasov07:01:18

I also really like this library https://github.com/jamesmacaulay/cljs-promises , it’s old, there’s more fancy ones nowadays, but this approach has never let me down… basically it allows to extend JS promises to return (let [[val error?] (<! a-promise)])

raspasov07:01:12

Core.async is not the most beginner friendly thing; errors can be confusing, etc; some people try to avoid it but I do like it; the trade-off is worth it for many of my use cases; it allows to easily synchronize not only HTTP requests but many different events in your application; for example I’m working on a React Native app, and using TensorFlow Lite; I need to wait for the library itself to initialize (doesn’t happen on application launch), and then some ML models to load before I proceed with different setup fns; so core.async is a great tool for that; Look at (promise-chan), useful for such cases

raspasov07:01:40

So above I showed a case where you launch-off multiple requests at the same time; that works nice for a demo and a one-off; in a long-lived application, I often find it desirable to have one global channel that processes responses one by one; Sometimes being able to reason about the sequence of incoming responses might be desirable (in situations around login, user setup etc); otherwise, the less you care about the sequence in which responses are being received, the better

raspasov07:01:19

In my experience, for ClojureScript, simply using (defonce a-global-channel) is enough… alternatively you can use https://github.com/stuartsierra/component

raspasov07:01:31

But I’d start with defonce…

seancorfield07:01:32

@U050KSS8M For the fake-http! function, instead of declaring a channel and returning it, could you just have the go block return the hash map (since go blocks automatically return a channel that, when taken, returns the last value in the go block?

seancorfield07:01:07

Also, for doall-`map`, why not use mapv instead which is eager?

raspasov07:01:09

Yes, you can; I just wanted to complete each channel with a random timeout

raspasov07:01:30

@seancorfield mapv works as well 👍

raspasov07:01:58

I just wanted to point it out, because it tripped me even after years of doing this 🙂

raspasov07:01:13

I just wrote (map …) and I’m like “why is this taking longer than 2 seconds” Lol

henryw37407:01:31

js/Promise.all would be the no-lib way to 'wait' for a bunch of stuff to be ready. in recent projects I've been happily using promesa lib which adds some nice sugar over js promises, (including as-if-sync macros like core.async). also worth mentioning, promesa works with https://github.com/juxt/clip (replacement for component lib) so you can have a system with async components

👍 6
raspasov07:01:06

@seancorfield I see what you mean…

raspasov07:01:22

Improved fake-http!:

(comment
  ;This takes at most ~2000 ms to execute
  (let [process-seq-of-channels
        (fn [chans]
          (a/go
            (loop [chans chans]
              (if-not (empty? chans)
                (let [ch   (first chans)
                      resp (a/<! ch)]
                  (println resp)
                  (recur (rest chans)))
                (println :done)))))
        fake-http!
        (fn [req idx]
          (a/go
            (a/<! (a/timeout (rand-int 2000)))
            {:resp req :idx idx}))]
    (a/go
      ;initiate requests, replace fake-http! with a function that makes an HTTP request and returns a channel
      ;MUST use (doall...) to send the requests right away!
      (let [resp-chans (doall (map fake-http! (repeat 10 {:req 1}) (range 10)))]
        (println :starting)
        (process-seq-of-channels resp-chans)))))

raspasov07:01:22

It has become a habit for me to sometimes make things around core.async extra verbose 🙂 It helps for debugging, (timbre/spy …) saves the day in many cases; But this is a good simplification

13tales07:01:30

@U051B9FU1 Yeah, it would’ve been easiest to fall back to JS, but I wanted to learn the “Clojure” way to do it 😅

raspasov07:01:34

@seancorfield @thomas.armstrong actually I just realized there’s also (pipeline …) in core.async in CLJS which is pretty cool… I’ve used it in JVM Clojure and it is really good; it can provide a more managed approach vs. the “manual one-off” I’m showing above; definitely worth checking out

raspasov07:01:17

@thomas.armstrong But it requires familiarity with transducers

13tales07:01:42

@U050KSS8M I think I’ll have to bookmark it for later. Feeling like I’ve got a lot to chew on here already 😄

13tales07:01:16

Are there separate docs for clojurescript core.async vs the clojure version? I know there are differences, but all I seem to find are the docs for the JVM version.

raspasov07:01:09

@thomas.armstrong one last word of caution; assuming you’re moderately familiar with JavaScript, and you don’t need crazy backward compatibility, I’d avoid most CLJS HTTP libraries and just directly call the browser/JS HTTP APIs that return promises or callbacks

👍 3
raspasov07:01:04

@thomas.armstrong I believe the docs are mostly the same

13tales07:01:09

Mmm. The lack of <!! etc tripped me up a little bit until I understood what was going on.

raspasov07:01:16

As far as (go…) stuff, it should all be the same; CLJS core.async is a subset of JVM core.async (of sorts)

raspasov07:01:04

Yes, only single ! in CLJS and no (thread…)

raspasov07:01:13

Otherwise, it should be the same

raspasov07:01:12

Ok calling it a night, have fun! 🙂

13tales07:01:30

Thanks again. Very much appreciated!

👍 3
cljs 3
13tales04:01:01

So, for anyone who’s curious about where I ended up on this, I went pretty far down the rabbit hole learning about core.async, watched Tim Baldridge’s 2013 talk, and I feel like I understand it all a bit better now. For context, my goal is to take some geographic coordinates, and a collection of dates, make API requests to retrieve sunset and sunrise times for the specified location for all of those dates, and then calculate some angles based on those times (that part not finished yet). Here’s my solution to making all the async requests and combining them into a single map:

(defn <get-times-for-date [lat long date]
  (let [build-result (fn [times]
                       {date times})]
    (go
      (-> (http/get ""
                    {:query-params {"lat" lat "lng" long "date" date}
                     :with-credentials? false})
          <!
          :body
          :results
          (select-keys [:sunset :sunrise])
          build-result))))

;; Still need to do the actual angle calculation
(defn <get-angles [lat long]
  (go
    (let [times (->> (mapv (partial <get-times-for-date lat long) dates)
                     (a/map merge)
                     <!)]
      (println times))))

Christian11:01:56

I feel like it is something easy, but I can't manage to make it work I want to use the elements of a vector as arguments for my function

(assoc {} :a 4 :b 3)
(def argvec [:a 4 :b 3])
(assoc {} argvec)??

Antonio Bibiano11:01:14

I think you are looking for apply

Antonio Bibiano11:01:42

(apply assoc {} argvec)

3
Christian12:01:31

For some reason I thought that I will get back this ({:a 4}, {:b 3})

Christian12:01:39

I was sure I tested that 😄

Christian12:01:19

Thank you

🙌 3
pavlosmelissinos12:01:58

What's the proper way to round a float to up to x decimal points, removing any trailing zeros (non-significant digits)? clojure.core/format satisfies the first requirement but not the second e.g. assuming the same syntax as format, this is the behaviour I'm expecting: (my-format "%.4f" 0.0001557) -> 0.0001 (same behaviour as format) (my-format "%.3f" 0.00001) -> 0 (`0.0` is also fine, but not format's 0.000) (my-format "%.8f" 0.1) -> 0.1(format outputs 0.10000000 here) The use case is creating an automated report so the output should ideally return a value, e.g. satisfy the string? predicate, rather than print the result. This could probably be done with cl-format but it doesn't seem like a good fit unless it can return a value rather than print to stdout

flowthing12:01:45

cl-format returns a string if you pass nil as the first argument.

🙏 3
pavlosmelissinos12:01:37

You're obviously right, don't know how I missed that :man-facepalming: Thanks!

flowthing12:01:33

Welcome. There's also with-out-str, which you might find useful with functions that print to stdout, but you obviously don't need it here.

👍 3
Daniel Stephens11:01:11

DecimalFormat from java interop might also be useful

(fn format-decimal [d]
   (some->> d
            (.format (doto (DecimalFormat. "0.0###")
                       (.setRoundingMode RoundingMode/DOWN)))))

😎 3
pavlosmelissinos12:01:47

Oh nice, that seems to be exactly what I was looking for! Couldn't for the life of me figure out how to make it work, so thanks a lot @ULNRSUK8C! 🙂

🎉 3
Noah Bogart14:01:23

quick question: i have a list of predicates, and a sequence of items. i want to remove all items from the sequence where at least one of the predicates is true. i'm looking for the counter-point to every-pred, something like any-pred. does that exist?

Noah Bogart14:01:16

ope, looking at the every-pred source, i see some-fn directly below it. i think that's what i'm looking for

flowthing14:01:37

Yeah, it's some-fn: (remove (some-fn odd? neg?) [3 -2 4]).

Christian16:01:10

Why is partial arguably better than an anon function?

;; good
(map #(+ 5 %) (range 1 10))

;; (arguably) better
(map (partial + 5) (range 1 10))
From: https://guide.clojure.style/#partial

Alex Miller (Clojure team)16:01:58

I'd argue it's not better :)

Alex Miller (Clojure team)16:01:20

so maybe we should all just agree that it's arguable :)

6
sheepy 3
Michael W16:01:37

partial is very rigid, you can't use it unless you are giving arguments in order. If you want to give a function the second argument instead of the first, you are stuck using anon functions. It's only a small step to just not use partial at all.

dpsutton16:01:44

style is fundamentally subjective. if you're inclined to look through it, allow yourself to be convinced or not. they are arguments about which style is better and up to you to find them convincing.

noisesmith16:01:23

I'd definitely use (partial + 5) instead of #(apply + 5 %&), I'd hope most would agree

👍 15
noisesmith16:01:15

in general I like when I can replace apply in anon-fn with partial

Alex Miller (Clojure team)16:01:21

Rich considers anonymous functions to be more idiomatic in Clojure than partial

Christian17:01:59

Thanks for the insight, I would not have seen the connection from apply and partial

sova-soars-the-sora17:01:56

too many arguments in programming : P

Harley Waagmeester17:01:54

when i run lein uberjar it gives me this warning -> Warning: The Main-Class specified does not exist within the jar. I used to make a uberjar with this project often, but not lately.

Harley Waagmeester17:01:01

I wonder what changed

Harley Waagmeester17:01:32

i have :main and :aot in the project.clj file.

Harley Waagmeester17:01:07

Leiningen 2.9.4 on Java 14.0.2 OpenJDK

Harley Waagmeester17:01:37

and :gen-class of course

Harley Waagmeester17:01:53

i don't see any classes anywhere, it isn't compiling anything, everything runs in cider ok

noisesmith18:01:58

@codeperfect a project doesn't need a compiled main in order to run, but if you don't create one for your uberjar, you'll need to provide java with some other entry point

noisesmith18:01:26

a popular choice is to skip aot-compiling and to pass your ns name as an arg to clojure.main

noisesmith18:01:06

if you have :aot set, make sure that the :main and aot options agree(?)

Harley Waagmeester18:01:36

i used a backup repository with an identical project.clj file and lein uberjar works there...

noisesmith18:01:50

in that case check your lein versions, and try running lein clean and see if that changes the result

Harley Waagmeester18:01:18

lein versiona are the same i did lein clean, what lein uberjar does is doing is putting the entire project directory tree into the standalone jar file, all the source code

noisesmith18:01:32

that's the normal behavior

noisesmith18:01:52

unless you explicitly ask for the source not to be included in the jar

noisesmith18:01:16

in fact a lot of standard tooling breaks if the libraries you use are not packaged that way

Harley Waagmeester18:01:32

but there are no class files of my code, and i don't know why it isn't compiling

noisesmith18:01:55

OK, the problem can be subdivided - uberjar is a supertask that calls the compile task if your project is configured to be compiled, you can try running lein compile as a task on its own and at least verify that works

noisesmith18:01:11

the likely issue here is that the config that causes compilation is erroneous

noisesmith18:01:06

either it doesn't compile, doesn't compile to the expected output location, or isn't being configured to compile

noisesmith18:01:42

also it might be good to move this conversation to #leiningen as it's definitely a lein / lein config issue

Harley Waagmeester18:01:27

lein compile creates the classes, but lein uberjar still isn't putting them in the jar, maybe i'd rather have a nice cup of tea and watch tv

Harley Waagmeester18:01:33

i do get a warning about ring -> Warning: parse-version not declared dynamic....(ring/util/parsing.clj:5)

Harley Waagmeester18:01:56

eh, some cookies with my tea

noisesmith18:01:59

if the classes are being created but are not showing up in your jar, make sure your target directory agrees with your uberjar classpath

noisesmith18:01:25

at this point it's probably easier to just look at the project.clj

Harley Waagmeester18:01:26

ah, the project.clj is different now, somehow ':prep-tasks ^:replace []' was put in there, i haven't used lein uberjar for months, working now 🙂

noisesmith19:01:14

yeah, it's a good practice to attempt to make an uberjar at least as often as you modify project.clj to head off subtle things like this

noisesmith19:01:45

(similar practice is recommended with optimized cljs compilation)

DG19:01:45

Hi, I'm wondering how can I short circuit a for loop in Clojure? I'm iterating an integer vector twice checking for specific sum, but would like to stop once I find a first match. How would one do that?

DG19:01:15

This is my currenct code:

(defn find-all-sums-to-2020 [expenses]
  (for [x expenses, y (rest expenses)
        :let [sum (+ x y)]
        :when (= sum 2020)]
    [x y]))

(defn find-sum-to-2020 [expenses]
  (first (find-all-sums-to-2020 expenses)))

noisesmith19:01:18

@diego559 for is not a loop, but it is lazy, you can just stop consuming it

noisesmith19:01:39

there's also the `:until` :while arg

noisesmith19:01:30

what you are doing there is the normal way to stop it early

DG19:01:27

So (first) function will evaluate only the first result and therefore stop the inner for from continuing, is that what you are saying?

noisesmith19:01:50

right, more precisely it never asks the inner for another value, so the value isn't calculated

noisesmith19:01:11

that's how laziness works - you don't stop it from the outside, you just never force it to execute, so it doesn't

DG19:01:32

Great, thank you

noisesmith19:01:11

the distinction becomes important when you have chunking (so asking for one item might make it decide to calculate 32 items) - you aren't forcing it to stop, you're asking it to calculate

J23:01:39

Hey all, I wrote a program to ping and get an async response from a server via a single function. It was just a test and I'm wondering if I can get feedback on design patterns, idioms, if there is a much better way to do this. Also, specifically on line 61, how can I run the load-foo calls in parallel, and then print responses, without having the program exit? https://gist.github.com/jaybutera/dabbcda1e89c8ffed33773d73b420907#file-main-clj-L60