Fork me on GitHub
#beginners
<
2018-07-03
>
justinlee01:07:34

in my UI code i often have to map 1 thing to 2 things. i typically do this using reduce and into. works great. But because the val and coll come after the f, the code is hard to read. So I wrote a reduceb that just puts the args in the order I want. My code now looks like this:

(reduceb [] (range 1 10)
  (fn [rows elt]
    (-> rows
        (into [elt]) ; in real life these two lines are more complicated
        (into [elt]))))
Is there a better way of doing this? Solutions I don’t like include naming the anonymous function so that I can use normal reduce.

Chris O’Donnell01:07:33

Do you mean something like this?

user> (into [] (comp (map (fn [x] [x x])) cat) (range 10))
[0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9]

justinlee01:07:49

i mean i guess that works. i’m really just trying to get the [] and the (range 10) up front because the anonymous function can be quite large at times. i find it easier to read the code knowing what the initialization and looping constructs are

Chris O’Donnell01:07:25

Ah, I understand now. Not sure I have an answer that you like, then.

anton01:07:37

this may seem like a nit-picky thing, but does anyone know why reduce-indexed doesn't exist?

noisesmith01:07:39

@antonoutkine there's areduce which provides an index arg for reducing arrays

noisesmith01:07:07

I don't know why there isn't an indexed reduce though, it's simple enough to make one out of reduce

anton01:07:38

right, especially given map-indexed and filter-indexed

anton01:07:54

although maybe I'm just being a perfectionist

andy.fingerhut01:07:18

There is no filter-indexed in core

anton01:07:48

keep-indexed

mg02:07:33

reduce-kv works for vectors

👍 8
josh_tackett03:07:56

anyone know what this is used for and where it comes from? ->Channels

hiredman03:07:12

the -> prefix usually indicates a factory function generated by defrecord

hiredman03:07:38

so it would come from a (defrecord Channels [...])

Mario C.04:07:35

Quick question about Midje: When I run the command lein with-profile <name-A>,<name-B> midje does it look in my test directory and run all the files there?

Mario C.04:07:48

If so, is there a way I can just have midje run one specific file?

Mario C.04:07:40

I want to test that a result that I get back is a map with a key :_id. I can't figure out how to write that in a midje checker

Mario C.04:07:15

I don't care about the value of the _id

seancorfield05:07:42

@mario.cordova.862 There's a #midje channel but I've no idea how active it is. Midje is... not idiomatic... so it's a minority testing engine...

seancorfield05:07:47

I like what it does with README files but I wouldn't use it for anything else. I'm trying to get Expectations up to speed on README files so I can stop using Midje but I'm not there yet.

seancorfield05:07:31

Midje brings a lot of "magic" to bear. My general advice would be to avoid it as a beginner. Learn how clojure.test works first -- since that's what all the tooling is based on.

Mario C.05:07:10

I didn't even know that Expectations existed! We are using midje in my internship so thats what I am learning but maybe I can bring this framework up to the team.

seancorfield05:07:26

Well, there's an #expectations channel too, but I'll still recommend learning everything about clojure.test first before deciding you don't want to use it 🙂

Mario C.05:07:02

@seancorfield Thanks! Will def start learning clojure.test!

grounded_sage05:07:23

how can I print emojis to terminal... is the a list that work with clojure?

seancorfield05:07:03

Clojure will print emojis just fine...

grounded_sage05:07:08

how do you use them? just wanting to use them in println's

seancorfield05:07:29

I don't understand the question. Emojis print just fine.

grounded_sage05:07:30

for me it's just printing the text. when I muck around with it I get an error lol

seancorfield05:07:55

So... you're not doing it right? Can you share what you've tried?

grounded_sage05:07:26

(println "U+2705 Finished inlining css")

manutter5111:07:15

The “U+2705” string is not how Clojure represents raw unicode. Just use \u instead of U+ like this

(println "\u2705 Done.")

seancorfield05:07:46

That's not a Unicode escape sequence.

grounded_sage05:07:47

sorry I don't quite know what that means

grounded_sage05:07:41

im just copy pasting them it seems to be working

felbit06:07:15

Why should I use clojure.set/differenceinstead of disj?

(defonce my-set (atom #{"1" "2" "3"}))
=> #{"1" "2" "3"}
(swap! my-set disj "1")
=> #{"2" "3"} 
(swap! my-set clojure.set/difference #{"2"})
=> #{"3"} 

felbit06:07:29

Seems equal to me in outcome, as long as I just have one item to be removed. Am I missing something here?

andy.fingerhut07:07:37

If your goal is to remove a single element from a set, then there is every reason to use disj

andy.fingerhut07:07:20

clojure.set/difference is most appropriate when you already have two sets, and want all the elements of the first that are not in the second.

felbit07:07:29

Thanks Andy. I was following a tutorial and stumbled over that part where the author decided to use clojure.set/difference in the same way I showed there. Didn't make sense to me.

matan06:07:31

@noisesmith > core.async only works inside one vm, akka works across vms / hosts iirc that's right, but serialization is a pain in the cross vm/host scenario ... something that's trivial with clojure

matan06:07:12

anyway even in a single vm, in what sense does core.async provide (or enable building) back-pressure?

noisesmith11:07:04

yes, >! and >!! both put backpressure on the caller

leonoel09:07:56

@matan @noisesmith CSP channels provide backpressure in the sense that IO operations happen only when the reader and the writer are both ready to transfer. That's why core.async communication operations are said to be parking/blocking : they wait for the other end to be ready. The actor model is fundamentally different because sending a message to an actor is a fire-and-forget operation, completing immediately without any control of recipient's ability to process messages. To implement backpressure on top of an actor system, an extra layer is needed to enable bidirectional communication between producer and consumer. This is basically what they did with akka streams, a declarative streaming engine that happens to be implemented with actors but where actors are mostly absent from user API because they're not backpressured as-is.

Mario C.17:07:44

Does anyone have any experience with a clojure REPL wrapping a result in a lazyseq?

noisesmith17:07:01

you called str

noisesmith17:07:15

if you use pr-str instead you get the normal printed representation

Mario C.17:07:34

No I am not calling str. I inserting to a postgres db.

Mario C.17:07:26

(sql/insert! @url
                              (keyword (:cars table-names))
                              {:body car-info
                               :_id  (.toString (:_id interview))

noisesmith17:07:27

OK, something called str, the repl doesn't wrap anything in a lazyseq on its own, but a lazy object returns a silly string starting with "clojure.lang.LazySeq" instead of something that looks like the contents

noisesmith17:07:30

.toString does the same thing str does on a single input

noisesmith17:07:37

user=> (str (map inc (range 10)))
"clojure.lang.LazySeq@c5d38b66"
user=> (pr-str (map inc (range 10)))
"(1 2 3 4 5 6 7 8 9 10)"

noisesmith17:07:58

user=> (.toString (map inc (range 10)))
"clojure.lang.LazySeq@c5d38b66"

Mario C.17:07:02

That should return a map. As it does but for some weird reason this repl is wrapping it in a lazyseq

noisesmith17:07:29

no, your repl isn't doing that, your code is, somewhere

noisesmith17:07:01

for example you used filter or map to update the value

hiredman17:07:09

are you sure insert! doesn't return a lazy seq?

noisesmith17:07:26

oh, I might be misunderstanding the problem here

Mario C.17:07:29

It does not

Mario C.17:07:56

It returns a map. seancorfield proved it to me a while back.

noisesmith17:07:16

what does the result that you have a problem with actually look like

hiredman17:07:35

are you sure you understood what he proved?

Mario C.17:07:14

The result I have problem with is that the insert! returns a map. But when I println the result it is a lazyseq

hiredman17:07:24

I work with sean and we use clojure.java.jdbc a lot, and the first insert! call I found in the code base calls first on the result

hiredman17:07:13

maybe you misunderstood what he proved to you?

Mario C.17:07:43

Well, he fired up a repl and showed me the result of insert! and it indeed returned a map.

hiredman17:07:19

are you sure he didn't use one of the other insert functions like insert-record?

Mario C.17:07:29

I am also doing (extend-protocol sql/IResultSetReadColumn PGobject...)

hiredman17:07:56

(oh, insert-record doesn't exist, not sure what I am thinking of)

Mario C.17:07:56

But that function doesn't do anything wraps it in a lazyseq

hiredman17:07:27

anyway, insert! returns a seq of generated keys

hiredman17:07:47

(which are likely wrapped in a map in some way)

Mario C.17:07:32

In general, operations return
the number of rows affected, except for a single record insert where any
generated keys are returned (as a map).

Mario C.17:07:14

(println (type (insert-function-that-does-saving-goes-here))) ==> clojure.lang.LazySeq

seancorfield18:07:35

@mario.cordova.862

boot.user=> (jdbc/insert! db-spec :status {:name "foo"})
({:generated_key 9})
boot.user=> (jdbc/insert! db-spec :status {:name "foo"} {:row-fn :generated_key :result-set-fn first})
10

pablore18:07:01

Coming from the js/redux world I’m accustomed to use reducers as pure functions that depends of the type of an action and it’s payload like so:

const my_reducer_example = (state, action) => {
   switch(action.type) {
       case: 'FOO':
            return state.map(foo_fn);
       case: 'BAR':
            return state.filter(bar_fn);
       default:
            return state;
   }
}
If I want to rewrite this in clojure, would multimethods be the way to go? Or maybe protocols?

pablore18:07:32

Given that I have multiple reducers which accept the same type of actions

seancorfield18:07:20

Also @mario.cordova.862

boot.user=> (type (jdbc/insert! db-spec :status {:name "foo"}))
clojure.lang.PersistentVector$ChunkedSeq

seancorfield18:07:32

That namespace docstring (`In general, operations return...`) seems to be referring to a very old version of the API. It's misleading, so I'll remove that.

Mario C.18:07:11

So if I understood you correctly the insert! function does, in fact, return a seq?

Mario C.18:07:54

@seancorfield The strange thing is that I don't get a result that looks like your example, ( { :generated_key 50 } )

Mario C.18:07:38

I actually get something that looks like ( { :id 1 :body "value" } )

Mario C.18:07:51

The map in there is what I actually want.

seancorfield18:07:13

I'm using MySQL. You're using a different DB.

seancorfield18:07:52

What actually gets returned from an insert -- specifically from a PreparedStatement that is configured to return generated keys -- varies between databases, unfortunately.

seancorfield18:07:17

PostgreSQL returns the entire row I believe.

Mario C.18:07:57

But whatever that what actually is, will be in a seq, regardless?

seancorfield18:07:41

Yes, a single-element sequence for insert!. A multi-element sequence for insert-multi!.

seancorfield18:07:24

Long ago, the API was different and you could indeed get back either a map or a sequence of maps. That's what that one line of the namespace docstring referred to.

Mario C.18:07:47

@seancorfield Thank you for clearing that up

Mario C.18:07:14

I was going crazy thinking I was doing something that was putting it in a lazyseq

justinlee18:07:23

@pablore Just to make sure: have you seen the re-frame project? It is the most redux-like front end solution out there and you won’t have to reinvent the wheel.

justinlee18:07:18

Arguably, the explicit verbosity of writing out the dynamic dispatch functions by hand is part of the charm of redux because it makes it easier to see what actions might modify a given piece of state.

pablore19:07:25

I know re-frame, but this is a backend app that I am making

justinlee18:07:38

But multimethods and protocols should work fine too.

josh_tackett18:07:00

@sundbp hey does anyone know how the #profile is determined when setting up a config file with: https://github.com/juxt/aero

Karol Wójcik19:07:25

I have some difficulties when it comes to understand ring handlers. In Node.js for example everything is asynchronous by default. What is a difference between the handler from Node.js and the handler from the Ring world? What are these asynchronous handlers and how to they differ from normal one in Ring? How the ring knows when the request is asynchronous or synchronous? As always thanks in advance for your responses. You are all great!

noisesmith19:07:58

In node.js you don't have threads so you can only get parallelism via async handlers. In ring your webserver will use a thread pool to handle requests, or it might use async workers or even combine the approaches. Typical ring code doesn't even have to care which approach the underlying server is using.

noisesmith19:07:33

if you have intense enough throughput that you need async for the performance boost, you'll probably end up using something based on netty, in my experience the aleph webserver (which offers its own ring adapter) works quite well

hiredman19:07:02

if you are ok with nodejs performance, you won't have to worry about performance on the jvm

hiredman19:07:20

tech empower has done multiple rounds of benchmarks of different webstacks, and nodejs with whatever database is never better then the middle of the pack

hiredman19:07:02

oh, sorry, I thought they only listed 100 when I said middle of the pack. nodejs is never in the top 50 out of 273 tested

Karol Wójcik19:07:09

Ok so to sum up I will never know when my server calls the asynchronous handler?

Karol Wójcik19:07:43

Or it's server dependant?

hiredman20:07:00

I am not sure, the async handler stuff is pretty new in ring and I've never needed it

hiredman20:07:39

I suspect you implement one or the other, and the ring adapter has to figure it out

hiredman20:07:43

it is a flag you pass to the adapter you use

hiredman20:07:44

ring is a spec that defines a bunch of different parts, the part that turns a given webserver (like jetty) is called an adapter

hiredman20:07:59

the official jetty adapter has an :async? option

Karol Wójcik20:07:30

What if there are many requests per server. Will the jetty auto scale the number of threads?

hiredman20:07:31

we have this kind of non-standard (it is netty based, so not that far from the beaten path) webserver I am using in a project at work, it provides some custom logic for dealing with a protocol built on top of http and websockets which we plugin in to which exposes an entirely not http like interface, and then I also have an in house ring adapter plugged in for http handlers

hiredman20:07:44

there is a configuration parameter if I recall

hiredman20:07:05

I think jetty defaults to a 50 thread threadpool

Karol Wójcik20:07:26

;OOO That's the huge amount

hiredman20:07:04

I've never had to change it, most of the jetty services I've exposed have been internal things, but you might want to adjust that if you are serving end users

hiredman20:07:12

50 threads is nothing

Karol Wójcik20:07:15

In Node.js I had only 1 thread 😛

hiredman20:07:43

I had a bug in some code once that caused the jvm to spawn something like 10k threads (that were sitting around doing nothing) and no one noticed it until at one point in a repl on a server I asked the jvm for a stack dump of all the threads

😱 4
Karol Wójcik20:07:27

I had no idea that the jvm threads are so cheap

hiredman20:07:01

linux is pretty ok at multithreading these days

Karol Wójcik20:07:16

Are there better systems for multithreading?

Karol Wójcik20:07:28

How can I check how many threads my app allocates?

hiredman20:07:58

jstack is pretty useful

hiredman20:07:53

(count (Thread/getAllStackTraces)) will tell you at the repl, you will be shocked at how many threads you have running

hiredman20:07:47

(9 with lein repl, 4 with clj)

Karol Wójcik20:07:11

hmm but is there a way to somehow check that in application?

Karol Wójcik20:07:24

Other than manually logging that value?\

hiredman20:07:14

yes, any kind of reporting/health check framework will tell you

hiredman20:07:53

but it isn't always very meaningful to know, so I wouldn't get hung up on it

Karol Wójcik20:07:49

Ok thank you! I'm really grateful that you spare your time on me.