funcool

A channel for discussing and asking questions about Funcool libraries https://github.com/funcool/
mccraigmccraig 2015-08-15T08:37:02.000012Z

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...

niwinz 2015-08-15T08:39:19.000016Z

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

niwinz 2015-08-15T08:39:35.000017Z

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

niwinz 2015-08-15T08:39:47.000018Z

so the usage of the either it make sense?

mccraigmccraig 2015-08-15T08:40:13.000019Z

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

niwinz 2015-08-15T08:41:17.000020Z

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

niwinz 2015-08-15T08:41:54.000021Z

(is just curiosity)

mccraigmccraig 2015-08-15T08:44:42.000022Z

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

niwinz 2015-08-15T08:45:20.000023Z

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

niwinz 2015-08-15T08:45:31.000024Z

I'm currently using promissum

niwinz 2015-08-15T08:45:44.000025Z

with the CompletableFuture of jdk8

niwinz 2015-08-15T08:46:11.000026Z

and I get the desired short-circuiting directly

niwinz 2015-08-15T08:46:16.000027Z

without using either

mccraigmccraig 2015-08-15T08:46:38.000028Z

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

niwinz 2015-08-15T08:46:48.000029Z

yeah...

niwinz 2015-08-15T08:47:17.000031Z

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

niwinz 2015-08-15T08:47:52.000032Z

I'm not pretty fan of manifold deffereds

mccraigmccraig 2015-08-15T08:48:32.000033Z

what don't you like about deferreds ?

niwinz 2015-08-15T08:48:33.000034Z

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

mccraigmccraig 2015-08-15T08:49:13.000036Z

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

niwinz 2015-08-15T08:49:55.000037Z

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

niwinz 2015-08-15T08:50:37.000038Z

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

niwinz 2015-08-15T08:51:13.000039Z

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

mccraigmccraig 2015-08-15T08:51:50.000040Z

did you see : https://github.com/ztellman/manifold/blob/master/docs/deferred.md

niwinz 2015-08-15T08:53:10.000042Z

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

niwinz 2015-08-15T08:53:22.000043Z

that only covers the "quick start"

mccraigmccraig 2015-08-15T08:55:47.000044Z

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

niwinz 2015-08-15T08:57:12.000045Z

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

niwinz 2015-08-15T08:58:08.000046Z

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

niwinz 2015-08-15T08:58:15.000047Z

\o/

mccraigmccraig 2015-08-15T08:59:17.000048Z

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

mccraigmccraig 2015-08-15T08:59:37.000049Z

(them being cats and buddy)

niwinz 2015-08-15T08:59:46.000050Z

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

niwinz 2015-08-15T09:00:23.000051Z

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...

2015-08-15T09:02:01.000053Z

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

niwinz 2015-08-15T09:03:14.000054Z

\o @dialelo

2015-08-15T09:03:18.000055Z

o/

2015-08-15T09:05:05.000056Z

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

mccraigmccraig 2015-08-15T09:05:41.000057Z

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

mccraigmccraig 2015-08-15T09:05:48.000058Z

i could use them though

mccraigmccraig 2015-08-15T09:07:23.000059Z

which would get me out of needing to combine applicatives

2015-08-15T09:07:23.000060Z

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?

mccraigmccraig 2015-08-15T09:07:50.000061Z

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

mccraigmccraig 2015-08-15T09:08:00.000062Z

or insane :simple_smile:

2015-08-15T09:08:16.000063Z

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

2015-08-15T09:08:37.000064Z

from what i read applicatives compose automatically like functors

2015-08-15T09:09:14.000065Z

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

mccraigmccraig 2015-08-15T09:09:14.000066Z

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

mccraigmccraig 2015-08-15T09:09:42.000068Z

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

2015-08-15T09:10:09.000069Z

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

mccraigmccraig 2015-08-15T09:10:11.000070Z

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

2015-08-15T09:11:01.000071Z

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

mccraigmccraig 2015-08-15T09:11:09.000072Z

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

2015-08-15T09:11:26.000073Z

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

2015-08-15T09:11:42.000074Z

well, there is an issue already

2015-08-15T09:11:46.000075Z

the one you opened

2015-08-15T09:13:29.000076Z

sorry, just woke up :simple_smile:

mccraigmccraig 2015-08-15T09:13:44.000077Z

:simple_smile:

mccraigmccraig 2015-08-15T09:16:29.000078Z

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

2015-08-15T09:17:39.000079Z

you mean the writer monad?

mccraigmccraig 2015-08-15T09:18:18.000080Z

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

2015-08-15T09:18:25.000081Z

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

2015-08-15T09:18:33.000082Z

@niwinz is going to add it back

2015-08-15T09:18:50.000083Z

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

2015-08-15T09:19:31.000084Z

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

2015-08-15T09:19:57.000085Z

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

mccraigmccraig 2015-08-15T09:20:30.000086Z

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

mccraigmccraig 2015-08-15T09:21:45.000087Z

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

mccraigmccraig 2015-08-15T09:22:37.000088Z

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

mccraigmccraig 2015-08-15T09:23:07.000089Z

so a mixed approach may well be best for clojure

2015-08-15T09:24:07.000090Z

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

2015-08-15T09:25:20.000091Z

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

2015-08-15T09:26:41.000092Z

i think a mixed approach is best for Clojure

2015-08-15T09:26:50.000093Z

use monadic types for things like asynchronous computation and error handling

2015-08-15T09:27:08.000094Z

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

2015-08-15T09:27:26.000095Z

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

mccraigmccraig 2015-08-15T09:28:10.000096Z

ah, ok, i wondered why you took them out

2015-08-15T09:30:18.000097Z

i'm currently looking at http://hackage.haskell.org/package/TypeCompose-0.9.10/docs/src/Control-Compose.html#%3A. for composing 2 applicatives or functors

2015-08-15T09:31:48.000098Z

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

mccraigmccraig 2015-08-15T09:39:53.000099Z

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:

2015-08-15T10:06:45.000100Z

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

2015-08-15T10:06:48.000101Z

with cats.core/join

2015-08-15T10:07:19.000102Z

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

2015-08-15T10:07:28.000103Z

except in very simple alet bindings

2015-08-15T10:07:35.000104Z

which are compiled down to an fmap

2015-08-15T10:12:23.000105Z

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

2015-08-15T10:41:23.000106Z

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

2015-08-15T10:42:02.000107Z

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

mccraigmccraig 2015-08-15T10:44:27.000108Z

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

2015-08-15T10:48:09.000109Z

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

2015-08-15T10:48:19.000111Z

that will have me busy for a few days i think

2015-08-15T10:48:42.000112Z

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

2015-08-15T10:49:03.000114Z

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

mccraigmccraig 2015-08-15T11:06:32.000115Z

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

niwinz 2015-08-15T13:35:15.000116Z

https://github.com/funcool/cats/pull/78 \o/

2015-08-15T13:54:12.000118Z

great, just merged it

niwinz 2015-08-15T14:01:19.000119Z

Thanks!