Fork me on GitHub
#funcool2015-08-15
>
mccraigmccraig08:08:02

hi @dialelo following on from https://github.com/funcool/cats/issues/75 am i missing something obvious ? i've currently got some code using a Deferred[Either] monad (Deferred being my own creation v. similar to canal but for manifold Deferreds rather than core.async chans), and i'd like to use alet instead of mlet for the async concurrency gains...

niwinz08:08:19

I know that in monads this is resolved using monad transformers, but I'm not know it the same concept applies to your situation

niwinz08:08:35

In any case, the manifold deferred already has the notion of error

niwinz08:08:47

so the usage of the either it make sense?

mccraigmccraig08:08:13

i'm not using the manifold error - they are being converted to either/left values

niwinz08:08:17

The question is, why not use builtin error facilities of the async value primitives that you are using?

niwinz08:08:54

(is just curiosity)

mccraigmccraig08:08:42

because then i get the either short-circuiting behaviour in multi-step computations

niwinz08:08:20

0.o, this is also can be get with builtin error handling

niwinz08:08:31

I'm currently using promissum

niwinz08:08:44

with the CompletableFuture of jdk8

niwinz08:08:11

and I get the desired short-circuiting directly

niwinz08:08:16

without using either

mccraigmccraig08:08:38

ah, yeah, good idea - i could use the on-error behaviour directly in the Deferred monad

niwinz08:08:17

the either is not necesarry if the abstraction already has a concept of the error

niwinz08:08:52

I'm not pretty fan of manifold deffereds

mccraigmccraig08:08:32

what don't you like about deferreds ?

niwinz08:08:33

I prefer using something like this https://github.com/funcool/promissum

mccraigmccraig08:08:13

i'm using aleph, so deferred was an obvious choice for an async primitive

niwinz08:08:55

yeah, but the manifold documentation is obscure and only based on code examples or api reference

niwinz08:08:37

It is a great library, sure. I don't have strong arguments for say bad things

niwinz08:08:13

it is just I don't like libraries without comprensible human readable documentation

niwinz08:08:10

Yes. Do you think this is a complete documentation...? is a simple readme

niwinz08:08:22

that only covers the "quick start"

mccraigmccraig08:08:47

yeah, they are quite basic. though deferred is quite a simple concept. the stream docs are worse and i had to do more code-reading there

niwinz08:08:12

The concept is very simple. You are right. But it not means simple concepts should not to be documented.

niwinz08:08:08

On the end... is my opinion... nothing more

mccraigmccraig08:08:17

ha, well i'm certainly not complaining about better docs, and the funcool libs i've used have great docs

mccraigmccraig08:08:37

(them being cats and buddy)

niwinz08:08:46

Is one of the main goals of funcool org...

niwinz09:08:23

the docs are not only about code examples. Are about how to install, how to contribute, the tricky cases, advaced use cases, the project maturity, quick start...

dialelo09:08:01

exactly, the situation is improving a bit but many Clojure libraries suffer from lack of good documentation

dialelo09:08:05

@mccraigmccraig: have you ended up using deferred's built-in error handling facilities?

mccraigmccraig09:08:41

@dialelo: i haven't , i'm using Either atm with a monad-transformer

mccraigmccraig09:08:48

i could use them though

mccraigmccraig09:08:23

which would get me out of needing to combine applicatives

dialelo09:08:23

so you want to be using Deferred[Either] inside an alet block and have: short-circuiting (from Either) and the bindings be the right values of either, am i right?

mccraigmccraig09:08:50

yeah, that was the idea... is that sane ?

dialelo09:08:16

seems reasonable to me, although if your async abstraction already supports error handling i'd go with it

dialelo09:08:37

from what i read applicatives compose automatically like functors

dialelo09:08:14

but i need to experiment using multiple applicative "layers" inside alet

mccraigmccraig09:08:14

yeah, from what i've read they can be composed generically, and each type doesn't need it's own transformer

mccraigmccraig09:08:42

there would still presumably need to be something which reified the composed applicative though ?

dialelo09:08:09

yep, I guess we have to implement a applicative type for nested applicatives

mccraigmccraig09:08:11

i can sidestep the problem for now by using manifold's error-handling though

dialelo09:08:01

great, I'm going to spend some time investigating nested applicatives

mccraigmccraig09:08:09

since there are already monad-transformers, it might make sense to add the applicative nesting to those... even if the implementation is just a call to a generic impl

dialelo09:08:26

definitely, i'm going to add that as an issue to cats

dialelo09:08:42

well, there is an issue already

dialelo09:08:46

the one you opened

dialelo09:08:29

sorry, just woke up simple_smile

mccraigmccraig09:08:29

i've been thinking i might want to add a writer to my contexts at some point (the thing that brought me to wanting alet is a high-level async cassandra client) to trace exactly what happened in a given op, so when i get around to that i won't be able to sidestep it in the way i can here

dialelo09:08:39

you mean the writer monad?

mccraigmccraig09:08:18

yeah... it's on a holiday from cats atm is it ?

dialelo09:08:25

you could also use an agent for logging, you get ordering semantics

dialelo09:08:33

@niwinz is going to add it back

dialelo09:08:50

but in our opinion is one of the things that can be achieved more idiomatically in Clojure

dialelo09:08:31

and doesn't provide much value in an "impure" language

dialelo09:08:57

of course we may be wrong, we're learning about all these abstractions by writing the library

mccraigmccraig09:08:30

true - this async stuff is the first thing i've done in clojure where there is real obvious value in the monad abstractions over and above other stuff already in the language

mccraigmccraig09:08:45

but then, once you've drunk the kool-aid, there seems to be value in being able to compose concepts and be able to rely on tested implementations which are designed to compose

mccraigmccraig09:08:37

though it's early days for me - i'm learning the abstractions to avoid going insane from callback hell simple_smile

mccraigmccraig09:08:07

so a mixed approach may well be best for clojure

dialelo09:08:07

yes, it is definitely valuable to compose these abstractions although our context management strategy needs improvements for making them easier to use

dialelo09:08:20

but stacking monads through transformers can get complicated once you have more than two layers

dialelo09:08:41

i think a mixed approach is best for Clojure

dialelo09:08:50

use monadic types for things like asynchronous computation and error handling

dialelo09:08:08

logging, state management and such are well solved problems in Clojure

dialelo09:08:26

so although we implemented reader, writer and state we didn't found ourselves using them at all

mccraigmccraig09:08:10

ah, ok, i wondered why you took them out

dialelo09:08:48

but don't worry, they are going in under the cats.labs namespace for the next release

mccraigmccraig09:08:53

interesting to hear of your experience implementing reader/writer/state and finding you were not using them... i guess i may well find the same... dunno yet. it's all pretty new to me simple_smile

dialelo10:08:45

one thing to be aware of when using composed applicatives in alet is that alet uses the monadic bind for removing applicative layers

dialelo10:08:48

with cats.core/join

dialelo10:08:19

so composed applicatives, in most cases, need to be monad transformers too

dialelo10:08:28

except in very simple alet bindings

dialelo10:08:35

which are compiled down to an fmap

dialelo10:08:23

i see that in our transformers we don't define the applicative instance, i'm opening an issue to solve that

dialelo10:08:23

i've started working on implementing functor and applicative for every transformer we provide

dialelo10:08:02

this way composing them and using them in alet will be possible and easy

mccraigmccraig10:08:27

oh, awesome... that will be handy - i'll stick with Either for error handling then... i'm already using Either for error handling in my web layer, so somewhere in my stack i will have to convert from manifold to Either error handling anyway

dialelo10:08:09

however i don't know when the PR will be ready, today i'm going to work on the core protocols chapter for the CLJS book we're writing https://github.com/funcool/clojurescript-unraveled/pull/98

dialelo10:08:19

that will have me busy for a few days i think

dialelo10:08:42

i kickstarted the applicative work in this PR https://github.com/funcool/cats/pull/77

dialelo10:08:03

so if @niwinz or yourself want to work on it i'll be happy to review!

mccraigmccraig11:08:32

ok, well i'm not blocked atm, because the monad-transformer impl i have working at the moment works fine... it's just a bit slower than it could be because it's not concurrent enough. if i get to the point of being blocked, or i need a diversion, then i'll have a go at some of the other monads

dialelo13:08:12

great, just merged it