funcool 2018-08-30

@mccraigmccraig this is what I got:

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

a bit better I should say

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

had a look, can't see one

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

(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)))))))

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

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

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

we also use a custom monad for hiccup markup

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

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

(rather than constructing new monadic types)

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

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?

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

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

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

so cats permits more programming consistency across our codebase

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

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

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

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

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

hmm i missed it, gonna take a look!

thanks for your comments

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

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

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

compojure-api and mount

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

how would cats help with validation ?

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

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

ah, yeah, short-circuiting we use heavily

it's invaluable

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

otherwise, either won’t accumulate errors

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

it seems so but I’m not familiar with it

I’m just googling for stuff

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

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

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

@kenny has left the channel