Fork me on GitHub
#beginners
<
2018-04-18
>
samedhi00:04:22

Silly question, but following along in the https://clojurescript.org/news/2018-03-26-clojurescript-command-line#starting-a-browser-repl I am entering the following

> java -cp cljs.jar cljs.main
Exception in thread "main" java.net.BindException: Address already in use (Bind failed)

samedhi00:04:43

How do I diagnose/modify what port is being used and causing an error?

samedhi00:04:37

Getting pretty much the same thing from https://clojurescript.org/guides/quick-start#clojurescript-compiler as well:

inferno git:(master) ✗ clj --main cljs.main --compile inferno.hello --repl
Exception in thread "main" java.net.BindException: Address already in use (Bind failed)

mfikes00:04:19

@samedhi By default it is port 9000

samedhi00:04:59

@mfikes lsof -n -i4TCP | grep 9000 gives me nothing, am I doing something dumb?

mfikes00:04:38

Try telnet 0 9000 as another test to be sure nothing is listening on TCP there

samedhi00:04:03

hello-world telnet 0 9000
Trying 0.0.0.0...
Connected to .
Escape character is '^]'.

samedhi00:04:18

… what have I done?

mfikes00:04:20

Hah! Nice. WTF.

mfikes00:04:35

You may have some port forwarding set up? Stange.

samedhi00:04:16

Got it @mfikes, think you are right, I’ll figure this out, at least I know it is me and not something actually wrong with the process.

mfikes00:04:24

Unless you have something odd in your /etc/hosts file. Hrm.

mfikes00:04:02

Right, problem is on your end unfortunately. It is unfortunate that you can't easily change the browser REPL port to something other than 9000 😞

samedhi00:04:29

You helped me along, I’ll twiddle with it some more, thank you for your help!

mfikes00:04:28

FWIW, the port is controllable. I just don't know how to do it via the configuration you can pass via cljs.main. You could clone and build the compiler with a different port, but that might be too much.

samedhi01:04:29

Ugh, ok, the key for me was the fact that everytime I kill the PID, a new process spun up at the same port.

samedhi01:04:07

That was dumb, but all I really needed to do was stop datomic from starting at startup. 🙂

matan10:04:59

atoms: do you ever constrain the functions that can be applied to an atom, using a certain code pattern? I know this question sounds a little OO, but code robustness is a concern also for functional programs. I was thinking of a generator function that returns the atom alongside the functions that can be operated on it. This just helps with code organization, does not enforce any restrictions. I find it a necessary balance though.

matan10:04:12

Admittedly, that is actually not very different from just placing all functions interacting with the atom ― in a namespace dedicated to the atom...

mfikes10:04:34

@matan An alternative is to add a :validator to an atom that ensures data in the atom always satisfies some invariant.

👍 8
noisesmith13:04:36

validators are underappreciated

matan14:04:23

:thumbsup:

matan14:04:45

Well, they have a cost at runtime

matan14:04:07

Anyway, thanks

matan14:04:31

Could you please remind me what are my options for mapping a collection without holding to its head and realizing it in full in memory? as I understand every element of the source collection is realized and kept in memory even if the only necessary access to it is during the map operation itself.

danm14:04:17

map doesn't hold onto the head. Not unless you've wrapped it in a doall to force execution for side effects

danm14:04:49

And even then, if all you care about is the side effects, use dorun

danm14:04:29

Or (run! fn coll), which neatly combines (dorun (map fn coll) into a single call

sundarj14:04:16

@carr0t close, but dorun and doall are synonyms, and run! is implemented with reduce

sundarj14:04:11

never mind i'm wrong

👍 4
sundarj14:04:29

dorun and doall are not synonyms

danm14:04:45

Indeed. doall retains the head. dorun does not

sundarj14:04:07

i missed that doall returned coll afterwards 😅

matan09:04:02

🙂 whoever picked these names for these functions could have arranged them better I guess.

matan09:04:02

So map does or does not? what's your way of determining that, as it's not heavily document I think? e.g. how do I determine it from their source code?

danm11:04:54

I looked at https://clojuredocs.org/clojure.core/map but the files on there are generated from the docstrings in the codebase. I mean, I guess I don't really understand your question. map doesn't put responses into a variable or anything. It just returns a result per item in the collection. It the thing that wraps map that decides whether to retain all those responses or not.

danm11:04:10

But because map is lazy, if you don't wrap it in something then it will probably go "Nothing is using what I return, so I just won't bother executing at all", which is not what you want if you're relying on side effects that occur within the mapped function

mfikes14:04:45

FWIW, the above is true in Clojure, but not in ClojureScript, which doesn’t have locals clearing.

matan09:04:48

Thanks. Very confusing this aspect. Are you certain map doesn't hold to the head? how would I determine this from looking at it's source? maybe I should SO this

cored15:04:47

hi all, what would be the fastest way to go from 0 to at least mid level in clojure, this in order to land a job using the tool?

sundarj15:04:57

@U096TPK1Q this blog series is good too: https://aphyr.com/tags/Clojure-from-the-ground-up other books worth picking up: Programming Clojure, and (for the more experienced) Joy of Clojure there's also a bunch of video courses on https://purelyfunctional.tv

cored15:04:41

oh yes, I have that same url bookmarked

cored15:04:06

@U61HA86AG I just need to actually make a plan to follow through because my intention is to land a job at some point

sundarj15:04:27

Eric Normand (the guy behind http://purelyfunctional.tv) also mentors people about jobs. he's on this slack too, you might wanna give him a shout. he's done a lot of thinking on this, see his other website: https://lispcast.com/hirable-in-clojure/

matan09:04:45

Late to the party, I think old books lack much of what's been added and even changed in the language over time. I'd say don't suffice with only old (beloved by some) books. Make a list of topics that you have to learn in parallel: transducers being at the top of the list, and the spec lib also somewhere in the list.

cored15:04:10

in terms of learning path

joelsanchez15:04:28

many people (including me) began with Clojure for the Brave and True

cored15:04:11

so do you think that using that I will get at least a grabs with the language ? @joelsanchez?

cored15:04:23

I have the living clojure book

cored15:04:37

and was thinking on starting there + the clojure koans

joelsanchez15:04:29

that's probably fine too, I was just citing a very popular and loved book

justinlee16:04:51

has anybody had any luck with managing async control flow without using core.async? i started down the cljs-ajax route, but it sure is painful to be back to callback hell

val_waeselynck16:04:02

I find Promises to be fine for most use cases, and to usually be a better fit than core.async for most request/response scenarii

sveri16:04:58

In combination with re-frame its pretty easy manageable. you still have one callback for success and one for error, but thats it.

sundarj16:04:50

heard good things about Manifold

justinlee16:04:14

@U06GS6P1N yes programming in clojurescript has never made appreciate promises so much. i’m thinking about trying httpurr and promesa. i wonder if those funcool people hang out here

justinlee16:04:33

@U0677JTQX setting aside all of the complexity re-frame adds, I’m not sure if helps if you have anything but a single async action and a response. callbacks are fine for that usecase, but if you have to do something complicated, like make a network call and then follow it up with subsequent calls based on the return value, the control flow gets blown to pieces really quickly

justinlee16:04:26

@U61HA86AG thanks yea i should have mentioned that i’m in cljs not clojure

sveri16:04:19

@U28E43ESX I am undecided on that as I have not used a library like promesa yet. But from a quick glance the only difference I can see is that you chain a function instead of a event listener and that the code is closer together than with re-frame. Is there anything else I am missing?

justinlee16:04:47

the error-handling channel is structured like try/catch. with callback/errback, you end up with piles of nested functions and then the errbacks are at the bottom in reverse order

justinlee16:04:49

you can also loop without crazy recursion

sveri16:04:18

I see, thank you.

justinlee16:04:28

at least, that’s what happens in javascript. i’m hoping promesa works like that

Jacob16:04:45

If I'm printing out some data, or writing it to a file, how would I check if a value is a string and if it is, then print it out with single quotes. For example I'm printing the string ASSET How would I add the single quotes so it prints like this 'ASSET'

noisesmith16:04:24

@jisaacs46: one way to do this would be to make a multimethod on the type of the object, where the method for string returns (str \' s \')

Jacob18:04:39

I'm trying to write a string to a file with single quotes like this (->> map-values (map #(str \' % \'))), but all the file has is clojure.lang.LazySeq@19f48b3b how do I get it to actually print out the strings?

seancorfield18:04:15

map produces a lazy sequence and println doesn't realize the sequence. You could either use mapv to get a non-lazy vector or thread the result into doall @jisaacs46

Alex Miller (Clojure team)18:04:03

println does realize a sequence

Alex Miller (Clojure team)18:04:20

but I’m assuming he’s not using println

Alex Miller (Clojure team)18:04:42

how are you writing the string into the file? spit?

seancorfield18:04:46

Ah, sorry, that was sloppy of me.

Jacob18:04:20

I'm using

(defn write-file [str]
  (with-open [w (  "whfs.sql" :append true)]
    (.write w str)))

Alex Miller (Clojure team)18:04:48

what string do you actually want written?

Alex Miller (Clojure team)18:04:48

like just pr-str on the original map-values may be closer to what you want

Jacob18:04:58

It may be, I'll try it. I'm trying to write a bunch of inserts statements, from a vector of maps i retrieved from the database, to a file

alwyn19:04:40

I am currently doing something similar lazily parsing xml log files using data.xml. Since doall retains the head, does it mean that all the data is stored in memory anyway at some point?

noisesmith20:04:42

@alwyn yes - but you can use dorun instead of doall to not retain the head or return a collection if that works

alwyn20:04:44

If I have the following code:

(with-open [rdr (io/reader "/home/alwyn/p/olslogF.txt")]
  (doall
   (->> rdr
        xml/parse
        :content
        (filter is-debug-realm?)
        first)))
Would doall retain head to the final sequence or the data as read by the reader?

noisesmith20:04:42

first already limits it

alwyn20:04:07

debug code 🙂 I'm trying to figure out how to actualize that filter function Currently it doesn't work because all it does is trying to fetch specific keys from the 'current' item in the sequence, but I suspect 'current' is not actualized yet.

noisesmith20:04:28

the item first sees is realized

alwyn21:04:36

so if there is no result, then there must be something wrong with my filter function...