Fork me on GitHub
#beginners
<
2019-04-08
>
Zachary00:04:31

Hey guys what is the most efficient way of importing large javascript libraries (in this case THREE.js) inside clojurescript?

orestis07:04:56

Same as any other library. Either use shadow-cljs as your build tool, or see the ClojureScript webpack guide https://clojurescript.org/guides/webpack

adam00:04:19

Why is this returning 3 instead of 1+1 + 1+2 + 1+3 = 9: (reduce #(+ 1 %) [1 2 3])

lilactown00:04:32

the reducer function takes two arguments. an accumulator and the current element

lilactown00:04:49

#(+ 1 %) is only using the first one, the accumulator

lilactown00:04:38

so you end up repeating:

(+ 1 nil) ;; => 1, which will be passed in to the next one as the accumulator
(+ 1 1) ;; => 2
(+ 1 2) ;; => 3

adam01:04:47

Hmm, I don't think I understand. This is still not working: (reduce #(+ 1 %2) [1 2 3]) (returning 4 instead of 9)

hiredman01:04:02

It seems like maybe you are trying this using clojurescript, not clojure

adam01:04:06

Correct, I am playing with Planck

hiredman01:04:58

Clojure proper will throw an error for your first example

hiredman01:04:55

Your second example is really the same issue, you need to use both the accumulated value and the element

hiredman01:04:09

It will likely be clearer to you if you use fn and explicitly list out the arguments and give then names

adam01:04:10

Thanks, I'll try that.

adam02:04:58

What I don't get now is why (reduce #(+ 1 %1 %2) [1 2 3]) is returing 8 instead of 9. Same with (reduce (fn [x y] (+ 1 x y)) [1 2 3])

hiredman02:04:54

Remove the reduce and write it out

hiredman02:04:31

(+ 1 (+ 1 1 2) 3)

hiredman02:04:48

you are expecting something like (+ 1 (+ 1 (+ 1 _ 1) 2) 3), so the question is what _ needs to be and where and how you communicate it to reduce

hiredman02:04:48

the doc string for reduce might be helpful there

adam02:04:27

I thought reduce would work like this: Step 1: 1 (from my vector) + 1 (hardcoded) = 2 Step 2: 2 (acculmated) + 2 (from my vec) + 1 (hardcoded) = 5 Step 3: 5 (accumlated) + 3 (from my vector) + 1 (hardcoded) = 9

hiredman02:04:22

but you have a function of two arguments, and one is missing in your step 1, so that cannot be what is happening

hiredman02:04:17

right? you step one doesn't have an accumulator to use, and reduce obviously doesn't make up an initial accumulator value from nothing

hiredman02:04:36

so in order to call your function it needs an item from the vector and an accumulator value

adam02:04:53

Ah, so: (reduce #(+ 1 %1 %2) 0[1 2 3])

adam02:04:29

Yeah, this works. Thanks for the explanation. I need to get more used to the functional way of thinking ๐Ÿ™‚

seancorfield02:04:44

The docstring for reduce is quite complex but it is also very specific about what happens.

If val is not supplied,
  returns the result of applying f to the first 2 items in coll
-- so the first call in your case was (+ 1 1 2) (just so you understand where @hiredmanโ€™s expression above came from).

โž• 8
adam13:04:42

Thanks for the very helpful addition. I see now. In the case of (reduce #(+ 1 %1 %2) [1 2 3]), I am getting 8 because: Step 1: 1 (first elm in coll) + 2 (first elm in coll) + 1 (hardcoded) = 4 Step 2: 3 (third elm in coll) + 1 (hardcoded) = 4 = 8

seancorfield02:04:28

It's much safer to always provide the initial val to avoid the somewhat strange cases (empty collection, one element, two-or-more elements).

johnj03:04:39

for a function, I don't know if I should use a named args or just accept a map, the fn has to create a map from the values given, some args are required, some are optional - what's recommended to do here?

seancorfield05:04:18

@lockdown- Accept a map, in general.

seancorfield05:04:52

Named arguments are good for functions that will only ever be called by humans but they don't compose well if they're called by other functions.

๐Ÿ‘ 4
vinurs08:04:05

how to split {1,2} to [1 2] in clojure?

Drake Nelson11:04:59

I haven't eval tool on hand, but I think into function will be solution. https://clojuredocs.org/clojure.core/into

practicalli-johnny12:04:41

@haiyuan.vinurs {1,2} is the same as {1 2} in Clojure, because commas are treated as white space. If you were asking how to create a vector from a map, then this is one simple approach

(vec {1 2})
;; => [[1 2]]

(flatten 
  (vec {1 2}))
;; => (1 2)

schmidt7308:04:53

@haiyuan.vinurs as in the string or the dictionary?

vinurs08:04:51

@henri.schmidt itโ€™s a string

schmidt7309:04:19

@haiyuan.vinurs then a regex would do the trick.

schmidt7309:04:25

or if you know your input is safe you could be really cheeky convert "{1,2}" => "[1,2]" and call read-string on it.

practicalli-johnny10:04:00

Is there a way to get partition-all or similar Clojure core function to partition (or group) starting at the end of a sequence? So if I had an argument of "abcdefg I would get a result (("a") ("bcd") ("efg")) Of course I could reverse before partitioning, just wondering if I missed something

clojurites_1911:04:44

({:xAxis 48}{:yAxis 35}) This is my map .I want value of only xAxis.

Sasho11:04:22

(:xAxis ({:xAxis 48 :yAxis 35})

practicalli-johnny11:04:25

If you have a single map of {:x-axis 48 :y-axis 35} then you can do (:x-axis {:x-axis 48 :y-axis 35}

clojurites_1911:04:11

this is not single map. How can i convert it to single map?

practicalli-johnny11:04:16

You could merge maps.

practicalli-johnny11:04:25

Or you could map over the collection using: (some :x-axis '({:x-axis 48} {:y-axis 35}))

practicalli-johnny11:04:56

or you can use map, but you also get a nil value because :x-axis only exists in one map (map :x-axis '({:x-axis 48} {:y-axis 35}))

clojurites_1911:04:36

if i want {:x-axis 48 :y-axis 35} then how to do it ??? above solutions giving me nil value

practicalli-johnny11:04:46

the above some and map functions work on the sequence of maps. If you want to combine the maps, then use (reduce merge '({:x-axis 48} {:y-axis 35}))

practicalli-johnny11:04:40

Remember, when using a list () as an argument (data) then you need to quote the list, '() or Clojure will try to call the first element of a list as a function.

clojurites_1911:04:10

Thank you .....it worked

bananadance 4
adam13:04:42

Thanks for the very helpful addition. I see now. In the case of (reduce #(+ 1 %1 %2) [1 2 3]), I am getting 8 because: Step 1: 1 (first elm in coll) + 2 (first elm in coll) + 1 (hardcoded) = 4 Step 2: 3 (third elm in coll) + 1 (hardcoded) = 4 = 8

Sasho13:04:48

Hey all ๐Ÿ‘‹ Iโ€™m using Visual Studio Code + Calva. In Clojure, is it possible to put a breakpoint on a line in the source file, stop execution there and start stepping in/over the code?

Alex Miller (Clojure team)13:04:29

It is generally possible (other tools like Cursive can do so via the JVM debugging API), but I don't know if Calva does it

Sasho13:04:25

Thank you for your answer.

practicalli-johnny13:04:30

@UHBCE1X7D ask on the #calva-dev channel, they are very responsive. As Calva is modelling itself after CIDER in Emacs, then Calva should have debugging at some point (if not already)

Sasho13:04:09

Will do, @U05254DQM, thank you ๐Ÿ™‚

Lennart Buit13:04:20

well, the debugging in Cursive is a bit strange sometimes. For example, you sometimes โ€œcontinueโ€ to the same line three times, because the form was a macro that happened to expand to multiple โ€œlinesโ€

Alex Miller (Clojure team)13:04:16

well, that's true of all Clojure debuggers, both from macroexpansion and having multiple expressions per line in the bytecode

Lennart Buit13:04:46

(mean no disrespect, I love cursive! just warning newcomers for that caveat!)

lilactown13:04:46

same is true in CLJS ๐Ÿ™‚ the places you can actually set a breakpoint in Chrome is a bit mysterious sometimes

Lennart Buit13:04:33

yeah, I guess both debuggers are made for non-functional languages

Lennart Buit13:04:51

(not sure how a functional language debugger would look tho)

lilactown13:04:12

I think it just has to do with the fact that thereโ€™s not a 1:1 correspondence with a Clojure expression and an expression on the host platform

lilactown13:04:21

I donโ€™t think itโ€™s functional vs non-functional thing

sotrhraven14:04:58

anyone seen illegal access when starting lein repl. just updated to 1.11.0.

Lennart Buit14:04:43

java 11 you mean?

Lennart Buit14:04:55

or clojure 1.10 ๐Ÿ˜›

sotrhraven14:04:43

clojure 1.10 opendjdk 1.11

Lennart Buit14:04:42

yeah, Java >=9 has a new module system that hides certain implementation details from you. They are slowly removing access to those implementation details. I am sure others call explain it better than me

Lennart Buit14:04:31

and already apparently have! Thanks Alex!

sotrhraven14:04:52

--illegal-access=deny, do I add this to my profiles.clj: :jvm-opts ^:replace ["---illegal-access=deny"] (that didn't seem to help)

Alex Miller (Clojure team)15:04:14

you have one too many --- there

Alex Miller (Clojure team)15:04:28

but this is the right place

sotrhraven14:04:23

I think this needs to be passed to the jvm. It isn't clear from the site where to pass it, especially for someone new to Clojure and using mainly the lein tool.

sotrhraven14:04:22

or perhaps an environment variable

CyberSapiens9716:04:31

if you guys had to name a temporary folder and a zip file, that later will be requested by the user front-end application. What would you use to name it? i was thinking on using a UUID

Alex Miller (Clojure team)17:04:25

The JDK has an api for this that can create unique things in an os-friendly location

victorb16:04:09

@cybersapiens97 make a sha1 of the content, set the sha1 as the filename. Instant collision-free ๐Ÿ™‚

victorb16:04:02

also gives the benefit of people being able to verify the contents of that specific file (but yeah, 99.99999999% of users won't care about that)

๐Ÿ‘ 4
elamje17:04:35

Hi, would anyone be able to explain a couple of things about Clojure spec? I am trying to wrap my head around how it compares to a static type system. I understand that it is extremely tunable and flexible (obviously different than static types), but what are some ways that it's not as powerful as a type system?

lilactown17:04:30

spec is used at runtime, so you do not get the ability to "check your program" by just adding specs and running a tool against your code

elamje17:04:33

Okay, thanks. Since Clojure is so extensible, could one devise a program that runs everytime before you compile code to basically do static type checking via spec?

elamje17:04:21

Like a middleware that checks against spec before clojure code gets read by the reader.

elamje17:04:01

Oh shite, I just realize what @U064X3EF3 messaged after you

elamje17:04:07

The answer to my question haha

Alex Miller (Clojure team)17:04:00

(Although Spectrum does this better than I would expect using specs)

๐Ÿคฏ 4
elamje17:04:28

In effect, is this library any different than having static type checking, or is it basically the exact same thing?

Alex Miller (Clojure team)17:04:04

It canโ€™t handle everything

Alex Miller (Clojure team)17:04:54

And it canโ€™t protect you from things that happen at runtime

Alex Miller (Clojure team)17:04:22

Ultimately, types are about proving things. Specs will not help you prove things.

haywood17:04:11

๐Ÿ‘‹:skin-tone-2: I have a map that has some metadata, I'm trying to read a key from it, who's value is a string, but I get a ClassCastException error, as strings are not able to have metadata

noisesmith17:04:49

sounds like you are flipping something, because metadata is a map, and it's allowed to have strings as both keys and values

haywood17:04:47

oh nm this works which kills my assumption on what was wrong

clojure
(def a (with-meta {:a "ok"} {:type "a map!"}))
(meta a) ;; => {:type "a map!"}
(:a a)

haywood17:04:00

I thought the last line would error

Robert Nikander19:04:14

Is there any reason I can't put docstrings on my deftype methods?

Alex Miller (Clojure team)19:04:00

How would you see them?

Alex Miller (Clojure team)19:04:54

deftypes can only implement interface methods and protocol methods, and those are the visible abstractions

noisesmith19:04:10

the method on a deftype isn't data that it owns, so it doesn't contain storage for a doc string - on the jvm methods aren't Objects

noisesmith19:04:29

nominally the doc should go on the protocol or interface owning that method

noisesmith19:04:59

(or on the type owning the method)

sotrhraven19:04:11

Poll: Leiningen or Boot?

sotrhraven19:04:10

wondering which is more used

sotrhraven19:04:47

clj and deps maybe

noisesmith19:04:32

leiningen is used more by far

Robert Nikander19:04:30

I like clj and deps so far. But my project is only 6K lines of clj/cljs.

Mno19:04:50

I kinda see clj being the standard in the future.

Mno19:04:06

but for now I stick to lein, just because the tutorials tend to use them.

sotrhraven19:04:54

is there a good tutorial on using clj and deps as far as workflow?

Mno19:04:38

though probably someone has something better.

Robert Nikander19:04:50

I got cider, repls, and cljs working with it. I doubt I'll ever use lein now.

noisesmith19:04:42

clj / deps is a tool for starting a repl, and a dependency manager, you will usually still need a build / packaging / deployment tool(s) for library dev or deploying apps

noisesmith19:04:27

there are ways to use deps and/or clj with lein or boot, and various relatively young build tools that use deps

gklijs19:04:32

They do are planning some cool things with boot, like being part native and supporting other languages. But for me it's still Leiningen, mostly because I now know how it works, and haven't really felt limited by it so far.

seancorfield20:04:26

@sotrhraven At World Singles Networks, we started with Leiningen back in 2011 (because that was the only choice), switched to Boot in 2015 (I blogged about that at http://corfield.org ), and then switched to clj / deps.edn completely last year (I have not blogged about that yet!).

noisesmith20:04:53

what do you use for build / package / deploy with deps.edn?

seancorfield20:04:27

Our code base is currently 81,461 lines (production source + tests)

seancorfield20:04:05

With a total of 986 lines of EDN (config files + deps.edn) across our monorepo.

seancorfield20:04:10

(822 lines are the various deps.edn files)

seancorfield20:04:35

We use (my fork of) depstar for build JAR files for deployment to production and we have a handful for small dev/build "tasks" written as Clojure namespaces containing -main functions that we invoke with clj and :main-opts in various aliases.

seancorfield20:04:24

Various clj/`deps.edn` tools available (including depstar): https://github.com/clojure/tools.deps.alpha/wiki/Tools

CyberSapiens9721:04:56

just to anyone who would like to try out: https://github.com/tengstrand/lein-polylith i'm a relative beginner on clojure web development, and i'm finding much more easier to work with my projects using Polylith, not only more easier but more fun and simple after you get how it works!

mathpunk23:04:38

does anyone have advice or reading on composing promises? i'm defining several simple but computationally-intensive processes, which I want to combine in a few ways. Some can be done in parallel, others must wait for completion of earlier ones.

noisesmith23:04:56

the big thing is that a Clojure promise (as opposed to other implementations like JavaScript) isn't an execution mechanism, it's a container that starts empty and gets filled exactly once

๐Ÿ‘ 4
noisesmith23:04:19

you can wait on it in a blocking manner but there's no "chaining" and it doesn't allocate a thread

noisesmith23:04:24

there are abstractions meant for managing parallel / async execution - and promises can even be part of it, but they will be a small part if they are (they are a straightforward way to make one thread wait for a specific action in another thread)

noisesmith23:04:01

AFAIK attend, then, recover, and fail from the page you linked were never implemented

mathpunk23:04:23

hmmmmmm. well i don't think what i've got is complicated enough for core.async, maybe I'm wrong --- my big problem is, I'm the guy who has to start all the different components of our app several times a day, to test different revisions and scenarios, and i'm getting v. tired of forgetting to start components, or having to restart some but not others, and none of it's in code

mathpunk23:04:12

i was inspired by a talk that suggested, maybe async is an elite carbon-fiber mountain bike, and i need a fixie ๐Ÿ™‚

noisesmith23:04:14

there are other mechanisms before core.async - eg. agents (which use a threadpool and abstract a value that you send functions to)

hiredman23:04:16

that page predates core.async, which to some degree supersedes it

hiredman23:04:01

it sounds more like you want something to start things and make sure there dependencies are started first, and do the reverse when you stop things

mathpunk23:04:20

yes. i figure i'm heading in the integrant direction but i've never written async in clojure

hiredman23:04:39

I haven't used integrant, but I am a big fan of component

mathpunk23:04:59

also on the table

mathpunk23:04:14

kinda figured i should figure out how to async, at least a little, before datafying it all

hiredman23:04:17

but I don't think any of that has anything to do with async/promise/futures/threads/etc

mathpunk23:04:47

yeah i guess you could say, i can see i have a problem with multiple pieces but i don't see the seams yet

hiredman23:04:31

you could always just create a dependency graph then toposort the graph and do whatever with that (which is what component does)

noisesmith23:04:42

there's also plumatic/plumbing/graph which has a data / value oriented approach to this https://github.com/plumatic/plumbing#graph-the-functional-swiss-army-knife

mathpunk23:04:51

i'll take a look

noisesmith23:04:17

graph lets you define data dependencies, then hand them to an execution strategy (single threaded or async)

mathpunk23:04:45

the promise thing came in, btw, when i was looking into ways to shell and i started playing with clj-commons-exec. it returns a promise instead of a value so I was thinking, huh, is it time to learn this aspect of clojure

mathpunk23:04:49

but it might be a red herring

hiredman23:04:14

you can get a plumatic graph kind of thing from a dependency graph and a topo sort as well https://gist.github.com/hiredman/71b71e4e07e7666fe1b9def9a476c765

mathpunk23:04:21

cool cool, i will check these out, thanks y'all

johnj23:04:39

When one does (defn foo [{:keys [a b c]]....), is the arg converted to a seq, then map, or to map directly?

noisesmith23:04:02

the arg isn't converted - the clojure.core/destructure function is used inside the defn macro to pull the values out of the map and bind them

noisesmith23:04:39

perhaps you were thinking of (defn foo [& {...}] ...) syntax? that starts with a seq of args and builds a hash-map

hiredman23:04:41

user=> (macroexpand '(fn [{:keys [a b]}] [a b]))
(fn* ([p__143] (clojure.core/let [{:keys [a b]} p__143] [a b])))
user=> 

hiredman23:04:10

user=> (macroexpand '(let [{:keys [a b]} y] [a b]))
(let* [map__146 y map__146 (if (clojure.core/seq? map__146) (clojure.lang.PersistentHashMap/create (clojure.core/seq map__146)) map__146) a (clojure.core/get map__146 :a) b (clojure.core/get map__146 :b)] [a b])
user=> 

johnj23:04:39

@noisesmith heh yeah, missed the & there

hiredman23:04:10

user=> (macroexpand '(fn [& {:keys [a b]}] [a b]))
(fn* ([& p__149] (clojure.core/let [{:keys [a b]} p__149] [a b])))
user=> 

johnj23:04:31

hmm, per @hiredman's example, looks like with & doesn't make any difference

hiredman23:04:03

it is different in that seq? will return true, and turn it into a map