Fork me on GitHub
#clojure-uk
<
2019-01-30
>
Rachel Westmacott09:01:42

I was pleased to discover that yada makes use of ex-data, so you can throw an ex-info with {:status 400 :body "Bad request: ..."} in your handler functions and have that returned as the http response.

Rachel Westmacott09:01:47

also, morning everyone!

mccraigmccraig09:01:03

how many other yada users are there here? you've given yourself away @peterwestmacott... anyone else?

👋 5
Wes Hall09:01:45

Apparently, I just discovered it.

Ben Hammond09:01:51

I use yada. My main bugbear with it is the heavy reliance on ztellman/manifold.deferred ; every interceptor call runs in a different manifold thread

Ben Hammond09:01:12

which can make it awkward to debug a misbehaving REST call because every step of the processing happens in a different thread

Ben Hammond10:01:35

In my head the main http server choices are yada and pedestal which boils down to a choice between netty or jetty

Ben Hammond10:01:54

is there much http-kit love on this channel (I don't love it)

rickmoynihan11:01:33

it’s ok — but IIRC I had problems with its handling of large request bodies… I think it topped out at 16mb or something. Could be wrong, but pretty sure I swapped it out for jetty.

Wes Hall10:01:53

I do use http-kit but honestly not with a great deal of thought. Something that will take my handler function and expose it as an http server. Yada appears to be an opportunity for me to go home and think about my life.

Wes Hall10:01:51

I already like the fact that yada offers this, "lean" option. Clojure seems to be an environment in which you write libraries for other people, and frameworks for yourself 😉. I can get behind that for sure.

mccraigmccraig10:01:18

@ben.hammond i have a solution to that problem (tracking ops spread out over many threads) waiting in the wings... it's going to be a little while yet before it's ready for primetime though

mccraigmccraig10:01:49

(and it involves the m word, so some people may be averse)

mccraigmccraig10:01:59

it's not really yada or manifold's fault - you are going to get callbacks on composed promises executed on different threads, it's just the nature of async

Ben Hammond11:01:59

um what is the m word

3Jane11:01:12

bet you it’s whispers “monoid”

😆 10
alexlynham11:01:24

is that the rws stuff you showed me?

Ben Hammond11:01:31

an anagram of o damn

dominicm11:01:24

Keep your technomancy away from my Clojure!

mccraigmccraig11:01:31

yes, magic @dominicm, but pure & functional magic, so it's ok

dominicm12:01:14

All magic comes with a price

10
otfrom12:01:38

I bet that monoid is in the category of endofunctors

mccraigmccraig12:01:31

that's the one @otfrom, award yourself a burrito

jasonbell12:01:25

Good morning.

otfrom12:01:34

I think I've figured out what I dislike most about monads and monoids - the lack of readily available analogies for me to think my way in and the terrible ones that people come up with instead

mccraigmccraig12:01:06

@dominicm the price perhaps being that every problem starts to look like it can be solved with more m-like thingies

dominicm12:01:48

Usually you accidentally end up killing your son or something

mccraigmccraig12:01:19

damn, spj never mentioned anything like that - perhaps he hasn't been entirely straightforward!

Wes Hall12:01:55

Every blog post I have ever read on, "monads explained", begins with, "There are many other blog posts that attempt to explain monads, but I found that they all do it badly, so here is my explanation". The rest of the post always reads like somebody explaining a dream that they had. All the basic facts are there, but there also seems to be some subjective context that cannot be communicated with simple language. I am pretty sure I get the general point, but I still find myself feeling like I haven't had the, "touch of the light", that seems to hit some people and change their life forever.

minimal12:01:05

I think expecting to feel “touch of the light” is the problem.

rickmoynihan12:01:33

Some things, especially beyond a certain level of abstraction, you can only really understand through experience. I don’t think monads are quite beyond that level of abstraction, but they’re close. I mean you can understand them superficially with a lot reading — but then you just don’t understand what the big deal is. Not that monads are really that big a deal 😉.

mccraigmccraig12:01:53

@wesley.hall the only thing that worked for me was using the things... this was an example of some code with utility in clojure which set me on the path - http://funcool.github.io/cats/latest/#manifold-deferred (since other ways i've come across of composing promises in clojure are either equally scary or not nearly so nice)

Wes Hall12:01:19

@rickmoynihan Yes, this is another impression I get. The analogy being much like trying to explain the rules of a game to somebody who has never played before. You know that once you understand all the rules, it is actually incredibly simple and logical, but when you try to serialise the idea into a sequential explanation it makes both you and them feel like you are talking them through brain surgery.

👍 5
rickmoynihan12:01:21

I think this is fundamentally what realisation is. Or say Satori in zen. You achieve a level understanding/realisation where things finally click, but you can’t quite articulate what has changed in your understanding. It’s just somehow deepened.

✔️ 5
Wes Hall12:01:33

@mccraigmccraig Thanks, will check out the example.

rickmoynihan12:01:47

Monads require that kind of realisation to happen for you to appreciate them… likewise for all the things beyond Monads, e.g. Arrows.

Wes Hall12:01:10

I do sometimes wonder whether I used up all of my, "penny drop" credits during 15 years of Java development and all the various OOP pattern exposure that comes with it. I may simply now be too old to have those moments again 🙂

Wes Hall12:01:21

"You must unlearn what you have learned" 😛

rickmoynihan12:01:48

Empty your cup.

mccraigmccraig12:01:13

empty cup, wet carpet

😂 5
rickmoynihan12:01:45

Actually I take some of that back… I think the big idea in monads can be understood; quite easily. It’s essentially composition, which is actually a much more general idea than Monads even. But monads show that composition can be applied to classes of things you might not have thought of. That class of things require certain categoric properties. If you have that particular set of properties (and obey the laws) then your class of thing is a Monad. And you can then target that Monad abstraction itself… e.g. do notation.

practicalli-johnny13:01:17

We have a room booked with SkillsMatter for Tuesday 5th February. Would anyone like to give a talk, workshop, demos, etc? No talks are booked as yet.

Wes Hall14:01:49

@jr0cket I can probably get involved if you like. The problem that I have is that most of the time people are more prone to asking me about the soft stuff. Building Signal as a tech co-founder, raising financing, putting a team together and the various trials and tribulations of that. Might be woefully off-topic for your intent though (I could probably talk about why we chose Clojure, or rather how long it took us to get there ;)). I've done a few panels, where the the panelists give their bios and then (ideally) get bombarded with questions, or (less ideally) simply share their own funny / informative / engaging / boring stories in an effort to entertain, and found these quite fun to do. Up for that too if you think it's appropriate, although there may be better people here than me for that, in which case, I would come to watch 🙂

Wes Hall14:01:07

tl;dr would love to help, but i'm boring.

yogidevbear14:01:23

No sure if there is a simple answer here, but in a thread-first macro, is there an accepted way to check if a value exists and then apply an update fn to it, otherwise simply return the original value? E.g.

(->
  ...
  ...
  (some? :the-key ... )
  ...)

guy15:01:39

Maybe (cond-> .. ) ?

guy15:01:03

ah someone said, sorry!

yogidevbear15:01:30

Hi @U08TUA46M 🙂 Was just about to say @ben.hammond had mentioned it 👍

5
yogidevbear14:01:56

Apologies if this question is a little vague 😊

yogidevbear14:01:46

Would using something like (merge) make sense here?

Wes Hall14:01:54

(some-> ...) ?

yogidevbear14:01:11

Goes to google 🙂

yogidevbear14:01:01

I think that would be more suited for the top level which wouldn't really apply here I think

Sam H14:01:40

got an example of what you mean?

yogidevbear14:01:02

Trying to think of a decent example without popping client code in here

Sam H14:01:34

check if a value exists and then apply an update fn to it, otherwise simply return the original value that reads as if you’d return nil if the value doesn’t exist

Wes Hall14:01:42

@yogidevbear Do you mean you want to do a thread-first macro where one of the steps is contingent on some predicate?

yogidevbear14:01:53

For example, I have a map that has certain mandatory kvs and some optional ones - e.g. {:foo "bar"} or maybe {:foo "bar" :baz "plop"}

yogidevbear14:01:21

And I need to run an update function on :baz - if it exists

yogidevbear14:01:37

And this update function is in the middle of a thread first macro

dominicm14:01:55

Medley has update-some

5
dominicm14:01:29

I guess I do. I don't think it was always called that. But maybe the name I'm using was a different library

yogidevbear14:01:47

Okay ta, I'll look into it

Wes Hall14:01:28

@yogidevbear Sounds to me like you need a function that takes a value (in this case your map), a predicate (in this case :baz) and a function to apply to the value if the predicate is true, or returning value as is, if the predicate is not true. My instinct is that something like this should probably be either 1) available in the core lib or 2) createable from composing functions in the core lib, but honestly the biggest issue I have with clojure is that I find it hard to remember the various core lib functions.... that said, easy enough to write something like this. Few lines. Might be an alternative to pulling in an entire library if you only need this.

Wes Hall15:01:11

(defn the-thing [v p f]
   (if (p v) (f v) v))

(-> {:foo "bar" :baz "plop"}
      ....
      (the-thing :baz #(update % .....))
      ....)
Now everybody can tell me about the core functions I forgot about 🙂

yogidevbear15:01:20

Dominic suggested something along the lines of:

(defn update-contains
   [m k & args]
   (if (contains? m k)
     (apply update m k args)
     m))

Wes Hall15:01:41

...and apparently I don't know my slack formatting either 😉, but you get the idea

👍 5
yogidevbear15:01:43

It looks fairly succinct so I'm going to test it out

Wes Hall15:01:55

apply-if would be a better name for my example than the-thing 😉

👍 5
yogidevbear15:01:24

Thanks for the feedback everyone ❤️ 💯

👍 5
Wes Hall16:01:52

@ben.hammond I was thinking that too, but cond-> doesn't let you thread into the predicate. The conditions have to be based on data that is separate from the thing you are threading through, unless there is something painfully obviously that I am missing.

Ben Hammond16:01:35

that is correct, but you don't need that too often

Ben Hammond16:01:13

oh I reread initial post

Ben Hammond16:01:34

yeah that's the smell of a threading macro that is too complicated

Ben Hammond16:01:56

break it up, let a bit of daylight in

👍 5