Fork me on GitHub
#funcool
<
2018-08-30
>
mping10:08:53

@mccraigmccraig this is what I got:

(->> (exc/success "")
       (cats/fmap parse-url)
       (cats/fmap open-connection)
       (cats/fmap to-stream)
       (cats/fmap slurp))

mping10:08:29

a bit better I should say

mccraigmccraig10:08:08

you could write a new thread macro which repeatedly fmaps, along the lines of ->>= ... if there isn't one already... i haven't looked

mccraigmccraig10:08:42

had a look, can't see one

mping10:08:24

and what about flatmap? I copy-pasted bind and did a recursive call but I was wondering if this is a need

mping10:08:29

(defn flatmap
  "Stack-unsafe, flatmapping version of `cats.core/bind`.
  Use at your own peril."
  [mv f]
  (let [ctx (cats.context/infer mv)]
    (cats.protocols/-mbind ctx mv 
                      (fn [v]
                       (cats.context/with-context ctx
                         (if (satisfies? cats.protocols/Contextual v)
                           (flatmap v f)
                           (f v)))))))

mping10:08:04

it should be able to do a safer version with some kind of fold or loop/recur I guess

mping10:08:10

may I ask how/if are you using cats? some complaints I read is that the monads end up infecting all functions

mccraigmccraig10:08:38

sure - by far our biggest use is to make async programming sane, so we heavily use the manifold deferred (clj) and promesa (cljs) promise monads

mccraigmccraig10:08:07

we also use a custom monad for hiccup markup

mccraigmccraig10:08:30

and our application context builder https://github.com/employeerepublic/deferst uses a deferred-state monad transformer

mccraigmccraig10:08:44

i haven't found monads infect everything - but that is perhaps because we mostly use monads over otherwise sane datastructures for our purpose

mccraigmccraig10:08:00

(rather than constructing new monadic types)

mccraigmccraig10:08:46

e.g. all of our promise monad stuff uses regular promises (deferred on clj or bluebird on js) so there's no odd infecetion

mping10:08:06

so I’m guessing manifold’s let-flow isn’t enough for your use case right? you probably mix and match deferreds with other monads - is this the case?

mping10:08:18

I’ve used manifold before but I’ve never used monads in clj

mccraigmccraig10:08:37

let-flow i think has power equivalent to cats alet - we use alet occasionally but mostly we use mlet which introduces stepwise operation

mccraigmccraig10:08:14

but i wanted to use the same idioms for async programming on both the front-end and back-end, and let-flow is clj only

mccraigmccraig10:08:43

so cats permits more programming consistency across our codebase

mping10:08:08

cool, didn’t know let-flow was backend only

mccraigmccraig10:08:30

i have heard of projects which create their own monad types having problems with infection - i think @jarohen had one - maybe yoyo ?

mccraigmccraig10:08:33

and it does seem that there are probably lots of places where monads make sense in other langs (with static checking) where they don't make sense in clojure

mccraigmccraig10:08:31

but when you want something to give you some well known and tested ways of dealing with a sensible datatype then i've found them to work well in clojure

mccraigmccraig11:08:09

ooo i just noticed the state monad got re-added to cats

mping11:08:37

hmm i missed it, gonna take a look!

mping11:08:41

thanks for your comments

mping11:08:54

we’re gonna migrate a rails app to clj soon and we’re evaluating stuff

mccraigmccraig11:08:19

out of interest (and if you are at liberty to answer 😬) what persistence and lib choices are you leaning towards ?

mping11:08:31

well, I guess we’re keeping our postgres db, so hikari cp, and either honeysql/yesql for db access

mping11:08:38

compojure-api and mount

mping11:08:08

we’re missing a validation story besides the coercion aspect of compojure-api, thats why I was looking into cats

mccraigmccraig11:08:33

how would cats help with validation ?

mccraigmccraig11:08:42

we use yada which has schema-based coercion/validation (probably similar to compojure-api)... and we also use schema/defn in selected other places throughout the codebase for further validation

mping11:08:34

well if I determine a request is invalid, I can build a pipeline of ops knowing that it will short-circuit

mccraigmccraig11:08:00

ah, yeah, short-circuiting we use heavily

mccraigmccraig11:08:16

it's invaluable

mping11:08:17

so mostly for that

mping11:08:52

I see that scala/cats has a validated which is an applicative functor, I guess a good exercise would be do something like that for clj/cats

mping11:08:04

otherwise, either won’t accumulate errors

mccraigmccraig11:08:07

oh, does that permit additional context to be added to errors by callers ?

mping11:08:36

it seems so but I’m not familiar with it

mping11:08:45

I’m just googling for stuff

mccraigmccraig11:08:31

oh, i see... not what i thought, but looks like it could be handy

mping11:08:31

in the end, when validation runs it seems you get an either

mccraigmccraig12:08:46

since we're all async we tend to use the error-condition of promises rather than either - which can (handily) usually be set just by throwing an exception