funcool

A channel for discussing and asking questions about Funcool libraries https://github.com/funcool/
2018-08-30T10:28:53.000100Z

@mccraigmccraig this is what I got:

(-&gt;&gt; (exc/success "<https://www.sapo.pt>")
       (cats/fmap parse-url)
       (cats/fmap open-connection)
       (cats/fmap to-stream)
       (cats/fmap slurp))

2018-08-30T10:30:29.000100Z

a bit better I should say

mccraigmccraig 2018-08-30T10:36:08.000100Z

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

mccraigmccraig 2018-08-30T10:36:42.000100Z

had a look, can't see one

2018-08-30T10:37:24.000100Z

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

2018-08-30T10:37:29.000100Z

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

2018-08-30T10:38:04.000100Z

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

2018-08-30T10:39:10.000100Z

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

mccraigmccraig 2018-08-30T10:40:38.000100Z

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

mccraigmccraig 2018-08-30T10:41:07.000200Z

we also use a custom monad for hiccup markup

mccraigmccraig 2018-08-30T10:41:30.000100Z

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

mccraigmccraig 2018-08-30T10:42:44.000200Z

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

mccraigmccraig 2018-08-30T10:43:00.000100Z

(rather than constructing new monadic types)

mccraigmccraig 2018-08-30T10:43:46.000100Z

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

2018-08-30T10:44:06.000100Z

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?

2018-08-30T10:44:18.000200Z

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

mccraigmccraig 2018-08-30T10:46:37.000100Z

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

mccraigmccraig 2018-08-30T10:47:14.000100Z

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

mccraigmccraig 2018-08-30T10:47:43.000100Z

so cats permits more programming consistency across our codebase

2018-08-30T10:52:08.000100Z

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

mccraigmccraig 2018-08-30T10:54:30.000100Z

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

mccraigmccraig 2018-08-30T10:55:33.000100Z

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

mccraigmccraig 2018-08-30T10:57:31.000100Z

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

mccraigmccraig 2018-08-30T11:00:09.000100Z

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

2018-08-30T11:05:37.000100Z

hmm i missed it, gonna take a look!

2018-08-30T11:05:41.000200Z

thanks for your comments

2018-08-30T11:05:54.000100Z

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

mccraigmccraig 2018-08-30T11:18:19.000100Z

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

2018-08-30T11:24:31.000100Z

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

2018-08-30T11:24:38.000100Z

compojure-api and mount

2018-08-30T11:25:08.000100Z

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

mccraigmccraig 2018-08-30T11:33:33.000100Z

how would cats help with validation ?

mccraigmccraig 2018-08-30T11:35:42.000100Z

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

2018-08-30T11:38:34.000100Z

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

mccraigmccraig 2018-08-30T11:39:00.000100Z

ah, yeah, short-circuiting we use heavily

mccraigmccraig 2018-08-30T11:39:16.000200Z

it's invaluable

2018-08-30T11:39:17.000100Z

so mostly for that

2018-08-30T11:39:52.000100Z

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

2018-08-30T11:40:04.000100Z

otherwise, either won’t accumulate errors

mccraigmccraig 2018-08-30T11:41:07.000100Z

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

2018-08-30T11:41:36.000100Z

it seems so but I’m not familiar with it

2018-08-30T11:41:45.000100Z

I’m just googling for stuff

mccraigmccraig 2018-08-30T11:45:31.000100Z

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

2018-08-30T11:46:31.000100Z

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

mccraigmccraig 2018-08-30T12:06:46.000100Z

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