Fork me on GitHub
#beginners
<
2018-09-09
>
henrik09:09:14

I wrote a couple of general functions for application of functions over a collection of collections of arguments. They constrain the number of parallel workers to a desired number. p-apply returns a channel on which results are streamed. p-apply-sync returns a collection of results, in the same order as the original inputs.

henrik09:09:52

It turns out I needed a solution for this as well. 🙂

dangercoder10:09:41

Why would I use rabbitMQ or something like that when I can use Core.Async?

dangercoder10:09:59

I don't need to talk to other machines right now.

dangercoder10:09:21

Or programs, (Which I could have done anyway using Http?)

borkdude10:09:01

persistence maybe?

schmee10:09:07

some reasons to use RabbitMQ over core.async are when you have too much volume to handle with a single machine and/or when you need fault-tolerance

henrik14:09:21

I have currently modelled quite a lot of stuff in core.async that will later handle volumes too big for one machine. It’s good for prototyping the logic, even if it will eventually run elsewhere on larger data sets.

Denis G12:09:14

is there a reason why if-let* (if-let which supports multiple bindigs) is not in standard lib?

Denis G12:09:01

same for when-let*

Denis G12:09:31

how can I conj only not-nil terms?

Denis G12:09:44

without always doing if-else

pvillegas1212:09:01

filter + conj

rakyi12:09:21

@denisgrebennicov this might be an XY problem. what are you trying to do? maybe you want (remove nil? [1 nil 2 nil 3 nil])

Denis G12:09:48

dunno. filtering AFTER insertion doesn't feel right. Can not I do it before insertion? Like (comp (partial filter not-nil?) conj) or smth

rakyi12:09:40

can you give us an example of input and your desired output?

Denis G12:09:57

it input is nil, return original seq, otherwise conj

Denis G12:09:04

without if-else 😅

rakyi12:09:29

you could write your own version of conj which would do that, but it would be highly unusual 🙂 thats why I asked for example to get a sense of what do you want to use it for, because there is most likely a more idiomatic way of doing it

rakyi12:09:48

so how would you use such function? I’d like to see a concrete example of data

Denis G12:09:51

just artificial actually I was thinking of a problem, having nested loops and then I realized how powerful for construct is. Especially with the :when clause which is more or less exactly what I need in my situation

deliciousowl12:09:56

what are you solving?

mfikes13:09:26

@denisgrebennicov Since into is based on conj, you could slip a nil filter in like this:

(into coll (remove nil?) xs)

mfikes13:09:31

If you want to “conditionally conj” this construct might be close to what you are after

(cond-> coll (some? x) (conj x))

Denis G13:09:47

looks sweet

dangercoder15:09:39

Is it bad practise to have a async/go-loop running forever? I have a batching go-loop that runs all the time since messages will come in all the time and I need to batch them.

enforser16:09:45

I don't think it is necessarily bad - provided it is being used throughout the life of the program then it makes sense to keep it around. I'm pretty sure there are a limited number of threads which are reserved for go blocks, so keeping one running forever would just occupy one of those threads (I think!)

mfikes16:09:44

An idle go block shouldn’t occupy a thread from that pool.

dangercoder16:09:05

Is it even "normal/good practise" to have channels who are pre-defined through def -s? In most programs I've seen who are using channels and core-async, they are always in a function like (let [chan ...)

mfikes16:09:10

I don’t know. I have a program that is even worse in that case 🙂 It defines a go-loop at the top level because that’s the whole point of the program is to wait for stuff, process, it and recur. (And this is in ClojureScript where there is only one thread.)

dangercoder16:09:27

The point of my program is to wait for users who are queing up, batch them together, send each user a notification, wait for accept/cancel, if too long -> send accept to the available queue again etc. So I think the go-loop would work 🙂..

borkdude16:09:11

@coderdanger is this hooked up to a websocket?

borkdude16:09:59

I bet you looked at sente already

dangercoder16:09:39

I've looked at it but I haven't checked it out properly yet. I was thinking about using the websocket/commmunication through Sente. But the batching and stuff, not sure if it supports that.

borkdude16:09:31

in the sente handler you could write to another core async channel. but if you have something working already, then that’s probably not worth it

dangercoder16:09:39

@borkdude Looks really neat. Will check it out. Still in the phase where I try different solutions 🙂

dangercoder16:09:53

Do you guys know any really good Core.async tutorial or reading material that is up to date. I really want to grasp this stuff. I've been looking into the following: 1. https://tbaldridge.pivotshare.com/categories/coreasync/1612/media (Seems a bit outdated.. but still good?) Havent looked into this one too much 2. https://www.braveclojure.com/core-async/ (Not in-depth, but good introduction.) 3. https://github.com/clojure/core.async/wiki Not in-depth

dangercoder16:09:54

Found theese as well: http://cognitect.com.s3-website-us-east-1.amazonaws.com/videos.html (Which @borkdude was refering to) Thinking about the http://purefunctional.tv ones, is https://purelyfunctional.tv/ any good overall?

sundarj17:09:16

i'm a big fan of eric normand, and the http://purelyfunctional.tv courses i've seen have been very well-done and helpful. can't speak for the core.async one specifically though

borkdude16:09:26

eh the link isn’t working, but you should find a webinar by David Nolen on core async

codonnell16:09:32

Not sure if they are exactly the same as the tim baldridge core.async videos that he had on his youtube channel, but I found those to be extremely useful for understanding how to solve problems using core.async at a high level.

yuhan19:09:40

Hi all, I'm trying to get started in clojurescript to make a sort of data-processing application with a simple web interface and the benefit of 'live-coding' via figwheel. I've worked through a few tutorials, but still a little confused and overwhelmed at the terminology and different templates available - is it recommended to start with the "lein new figwheel" template and build up from there? Or should I go with something more full-featured like the figwheel-main, reagent-frontend or reagent templates?

yuhan19:09:08

Just to note, I've never done any JS web development before so some of the terms like React/client/server/devtools in the bigger templates are quite foreign and I'm worried they might be overkill to deal with all at once... Would be really grateful for any guidance or references! Thanks 😄

deliciousowl19:09:19

hey, how well do you know JS?

deliciousowl19:09:37

or other languages

yuhan19:09:10

I'm pretty proficient in Python, and familiar with FP from Haskell and F#, also dabble in Emacs Lisp

yuhan19:09:04

No experience with JS so far unfortunately, it's the main reason I'm going with Clojurescript for a easily portable web app

seancorfield19:09:45

@qythium You say you're not familiar with "terms like ... client/server ..." -- are there specific questions you can form to ask us about those terms?

yuhan19:09:57

No specific questions in particular, just unfamiliar with the web dev framework as a whole - as far as my application is concerned it doesn't have to connect to the internet or perform any complicated transactions. The browser should just be there to provide a runtime environment and UI canvas. But I start browsing through all these templates and guides and they have different clj/cljs/cljc folders and references to client/server architecture - not sure if they are relevant to my use case, before spending time trying to get my head around the concepts

john19:09:34

What do you want to run your data processing?

john19:09:52

clojure?

john19:09:31

some "desktop apps" are built on electron these days, where you'll end up with "client/server" language, but node is the server, so you're still doing cljs on both "sides"

yuhan20:09:27

I don't quite understand, sorry 😅 What 'sides' are these?

yuhan20:09:15

Everything is taking place on the same machine, right? Just to clarify

john20:09:23

I just bring that up because if you look for "clojure desktop app" you may end up seeing some codebases that are electron based, which will further confuse you 🙂

john20:09:41

lol right

john20:09:22

It's "client/server" but on your desktop, because the web was built on that client/server architecture

yuhan20:09:43

yeah I was confused by the nodejs/electron stuff as well - should I be considering all that?

john20:09:14

It's a much different path that choosing clojure with a built in webserver like jetty and serving your app that way

john20:09:24

but the clojure version will have slower start up time

yuhan20:09:31

startup time isn't really a concern

john20:09:15

then you could use any of the standard web templates, like luminus

john20:09:35

and just package it up as a jar

yuhan20:09:45

ah, that's in Clojure not cljs?

seancorfield20:09:23

You could just write a console app in Clojure for your data analysis.

seancorfield20:09:48

Unless you specifically want to learn to build web apps and user interfaces?

yuhan20:09:49

will packaging as jar affect portability? We want to make it as simple as possible to just run in a client's browser without any dependencies

seancorfield20:09:11

A JAR built with Clojure will not run in a browser...

yuhan20:09:35

yeah I figured as much

john20:09:16

But a jar can have a jetty server built in

seancorfield20:09:02

Right, you can have a full web app in a JAR file that starts it's own server -- which you can then browse in any browser (with that server running locally).

john20:09:33

But building your analysis app as a standalone cli app, which you can build a web service over, is considered good practice too

yuhan20:09:43

Having a simple user interface is a major reason for doing this, I thought it would be easier to leverage the browser UI frameworks than figure out a full fledged desktop app

yuhan20:09:29

Are there any disadvantages to doing everything in clojurescript? Instead of splitting some bits into a jar and having to host the JVM

john20:09:47

probably depends on the analysis being done

yuhan20:09:50

because of library support?

seancorfield20:09:50

@qythium So this would be completely self-contained? Users would enter data and it would do the calculation and display it? No databases, no files on the file system?

yuhan20:09:45

no, it has to interact with the filesystem to write output files

seancorfield20:09:14

Browser-based applications are not allowed to do that, in general.

yuhan20:09:15

but no databases

john20:09:33

Are you more experienced with js or java?

yuhan20:09:06

neither, although I've done C# before..

john20:09:32

I may be biased, but I think interacting with the filesystem and other system level things are way easier on the jvm than node (which most electron type things use)

john20:09:22

But for folks that know all about node and the js ecosystem, they may have an easier time on that stack

yuhan20:09:52

Oh okay, the fs library I was looking at is nodejs specific

john20:09:23

yeah lots of async

seancorfield20:09:29

Either way, if you have file system interaction, you're looking at a client/server app -- a ClojureScript user interface (browser-based web app) talking to either a ClojureScript/Node.js or Clojure/JVM server-side app.

yuhan20:09:07

okay, so the server-side app is what does the data processing

yuhan20:09:49

and it somehow communicates asynchronously with a separate client app which runs in the browser?

seancorfield20:09:35

The client app can make simple HTTP requests (GET, POST) to the server app, which responds with HTML (web pages or fragments) or JSON (data)

yuhan20:09:38

Does this setup with luminus and clojure jars all work with figwheel live code reloading? I tried out a cljs tutorial with it and really liked the workflow

seancorfield20:09:09

You can have a similar workflow on the JVM with a REPL.

john20:09:14

if you don't need a db, you prolly don't need all of luminus

john20:09:33

a simpler template will do

seancorfield20:09:41

(i.e., both client -- in the browser -- and server -- on the JVM can have the same live coding workflow)

john20:09:40

luminus is good to learn though, in general

seancorfield20:09:24

Yeah, definitely worth learning Luminus. The Web Development in Clojure book is based on that I think...?

seancorfield20:09:26

Yup, React.js, Reagent, Luminus...

john20:09:02

I believe so. I prefer more pure clojure stacks myself, but in the real world, working with other dev shops, you're going to need to learn how to interface with other common web stacks and skillsets. It's pragmatic in that way.

john20:09:09

So it was really helpful having learned luminus' methods for some projects, while we'd usually run with pedestal for green field projects

seancorfield20:09:20

At work we have Ring + Compojure (mostly, we have one Ring + Bidi app) and we generate HTML with either Selmer (mostly) or Hiccup. And we have independent front end apps based on React.js that talk to them via REST (HTTP with JSON).

yuhan20:09:38

Hmm, I think I'm starting to grasp it a little better - thanks for the help so far!

john20:09:03

chestnut is a popular template, if you haven't heard of that one https://github.com/plexus/chestnut

Space Guy20:09:27

Is there a standard setup for figwheel-style 'reload as you save' for JVM-side code? I've found either "eval bits of it manually" or "build your own file-watcher out of hawk + tools.namespace + etc"

yuhan20:09:46

Ah, chestnut looks interesting, thanks! I hadn't come across it while searching

seancorfield20:09:58

My natural workflow is evaluating code as I type forms in -- I don't even save the code in that workflow.

john20:09:56

me too. I think cider has an experience like that, but I just use the repl directly

seancorfield20:09:09

I type into source files (or test files), evaluate forms as I go (and and that includes running tests too). I save from time to time and re-eval whole files. But I don't actually like the load/run-on-save workflow... I prefer to have more control.

seancorfield20:09:43

I almost never type into the REPL these days.

john20:09:03

It makes more sense when programming reactive UIs

john20:09:24

(the whole save, reload thing)

yuhan20:09:12

Yup, coming from python/jupyter notebooks using the eval-defun-at-point approach was quite natural

seancorfield20:09:46

Have you looked at the Gorilla REPL @qythium? That's supposed to be very close to the Jupyter model.

Space Guy20:09:55

I guess that works. I've used 'gorilla-repl' (notebook-style) for a few tiny things and there's always a lot of tracking "wait, I need to re-run cell 1 then cell 3 then ..."

seancorfield20:09:32

Yeah, that would be the reactive UI aspect of things. There's a lot less of that on the JVM.

john20:09:15

Well, he means evaling forms at a time, rather than whole namespaces

john20:09:34

In clojure, you want to eval whole namespaces less often

yuhan20:09:07

That looks interesting as well.. hmm

yuhan20:09:12

But back to the previous suggestion, the overall idea would be to make a pure Clojure CLI tool and interface it with a react web app which also runs on the JVM?

john20:09:25

I've heard bearded people say that it's best to structure your app as a cli app first... get your data interface squared away first. Then, when you build the gui version, you can build on top of those apis

john20:09:42

but then you can always test directly against the data apis, separate from the gui

john20:09:58

seems to have been good advice generally

john20:09:06

You can build directly over the apis, from clojure... you don't have to interface with it via a socket, but keep the web rendering stuff logically different. And a good way to enforce that discipline is to have a cli entry point for your app that does all the processing functionality.

yuhan20:09:55

Yeah that sounds like good advice

yuhan20:09:37

In that sense, it shouldn't matter what language the app providing the API was written in? Will it be ill-advised to do a F# data-processing CLI tool and try to interface it with the Reagent app?

john20:09:00

Well, part of the exercise is to learn clojure, right? Part of the sweet spot is how clj and cljs work together. I'd recommend trying a full clojure stack.

john20:09:34

But part of the awesomeness of cli tools that are posix compliant is that you do it however you want, yeah.

yuhan21:09:29

There's also OS compatibility issues which I've run into with F# - I guess jars are supposed to mostly get around that

yuhan21:09:24

Okay, will give your advices and the chestnut library a spin, maybe come back with more specific questions later - thanks so much for the help! 🙂

seancorfield21:09:05

The nice thing about building REST APIs is that they're easy to write tests for in Clojure using clj-http, for example. As we've been building out our REST API over the last year or so, we've written tests first for all the error cases and happy cases we think we need per the requirements, and then writing enough logic to make those pass (even if the underlying systems are mocked to use canned test data etc). That way we can test the full HTTP authenticated request with headers etc and the various HTTP verbs and be fairly confident that there's a solid REST API that the front end folks can build and test against.

seancorfield21:09:20

In fact, before we started using Clojure for the REST APIs themselves, we started using Clojure to write the tests for those APIs. So, yes, in answer to @qythium’s question from half an hour ago, the REST API code and the tests and the front end can all be in different languages if you want.

yuhan21:09:00

one quick last question, the chestnut template has several choices of React wrappers - Om/Om-Next/Reagent/Rum/Reframe

yuhan21:09:28

Any reason I should choose one over the other at this stage, and will I be able to switch easily later? Lots of the tutorials I saw have been using Reagent

borkdude21:09:50

@qythium Reagent is the most widely used and also the easiest to get started with.

yuhan21:09:21

Got it, thanks! I was wondering why it had Om as the default.

borkdude21:09:44

chestnut started as an om template back in the day

pvillegas1222:09:09

With a deps.edn project, how do I run a repl from emacs? cider-jack-in fires a repl but does not import the required libraries. Running clj from the project root works

pvillegas1222:09:40

I keep getting Could not locate ... in the classpath

seancorfield22:09:53

@pvillegas12 Do you have the latest version of CIDER etc installed? Support for clj in CIDER is pretty new I think...?

seancorfield22:09:11

Maybe ask in the #cider channel?

pvillegas1222:09:45

just reinstalled it, I’m on 0.18.1snapshot

seancorfield22:09:38

Sounds recent. I'm afraid I haven't used CIDER for a while so I don't know what to suggest...

pvillegas1222:09:02

I’m trying to connect to an nrepl with clj directly

pvillegas1222:09:29

but I’m hitting other problems like the cider-nrepl problem

seancorfield22:09:40

Hmm, I remember figuring out how to get clj to connect to an existing nREPL server instance and it was non-trivial -- but that's not really the use case it's designed for.

seancorfield22:09:37

Once you have an nREPL server instance up and running, you can connect to it from editors, or lein / boot ... but those are designed as nREPL clients.

pvillegas1222:09:39

What I want is to send expressions from emacs to clj

seancorfield22:09:33

Yeah, I would expect CIDER to be able to start an nREPL server instance via clj and send code to it (just as it can start nREPL server instances with lein or boot).

pvillegas1222:09:54

I guess my issue is an alias one

seancorfield23:09:11

Hopefully someone will answer your question in #cider -- I see you asked there.

pvillegas1223:09:12

I have some dependencies in the dev alias, that’s why it can’t read the depdencies correctly

seancorfield23:09:34

Ah, so you probably need to edit the command before it starts the REPL. Try c-u m-x cider-jack-in and it should offer the command before it runs it. So you should be able to add -A:dev to the command and then press return.

pvillegas1223:09:26

not getting the command to edit it:thinking_face:

seancorfield23:09:56

(btw, that shows how to start an nREPL server with clj -- where you could specify the alias -- and then connect to that running server with CIDER, as a workaround)

seancorfield23:09:42

Reading over that page, it looks like you can customize the cider-clojure-cli-parameters variable to include your -A:dev but that's going to be a global change...

dpsutton23:09:55

If you look up dir locals you can make it override that var inside your project directory