These are chat archives for ramda/ramda

1st
Feb 2017
Juan Lulkin
@joaomilho
Feb 01 2017 15:11
@Bravilogy I guess you can use http://docs.folktalejs.org/en/latest/api/control/async/index.html#control.async.control.async.fromPromise instead of wrapping axios.get yourself
Bravi
@Bravilogy
Feb 01 2017 15:14
@joaomilho hmm never seen that one. are there any good examples of folktale stuff?
there are loads of these PromiseConstructor → Task(α, β) → Promise(α, β), but no idea how to use the actual function
Kirill Rogovoy
@kirillrogovoy
Feb 01 2017 15:17

Hi, guys! I'm wondering whether there's a way to efficiently handle promise-returning functions inside of my composing functions (e.g. pipes). I mean, Ramda is great to write business (hence non-IO) logic, but I've been struggling to use it with async stuff.

I even created a tiny pipe replacement which has the same API as Ramda.pipe except the resulting function handles promises internally and always returns a promise: https://github.com/kirillrogovoy/promised-pipe

Anyway, how do you guys fight this issue in real world projects? Or am I doing something wrong at all?

Aldwin Vlasblom
@Avaq
Feb 01 2017 15:18
R.pipeP
Aldwin Vlasblom
@Avaq
Feb 01 2017 15:19
@kirillrogovoy :point_up:
But personally I don't use promises, but rather monadic alternatives like Fluture (by yours truly ;)). This allows compositions to made quite simply using R.map and R.chain and stuff.
Stefan Rimaila
@stuf
Feb 01 2017 15:23
Also alternative to promises (depending on how they fit in) would be to use streams instead. RxJS is a bit overkill for that, but lately my experience with Kefir has been positive.
Denis Stoyanov
@xgrommx
Feb 01 2017 15:25
@kirillrogovoy Kleisli composition + reduce that all what u need for create pipeP.
Aldwin Vlasblom
@Avaq
Feb 01 2017 15:26
Kefir, Most, Flyd, etc. I think Streams are fitting for environments where events may occur arbitrary amounts of times in arbitrary orders, like in browsers or web-socket servers. Promise alternatives play a big role for me in the classic server setting, where there's a request, some async processing followed by a response.
Denis Stoyanov
@xgrommx
Feb 01 2017 15:26
@stuf rx/most/bacon
@Avaq I agree with u
Stefan Rimaila
@stuf
Feb 01 2017 15:26
@xgrommx Yeah, at least from what I've seen people have moved to Kefir from Bacon.
@Avaq good point, yeah, too
Denis Stoyanov
@xgrommx
Feb 01 2017 15:27
@stuf most more preferable =)
Aldwin Vlasblom
@Avaq
Feb 01 2017 15:27
I would also recommend most.
Denis Stoyanov
@xgrommx
Feb 01 2017 15:28
MOnadic STreams :smile:
Stefan Rimaila
@stuf
Feb 01 2017 15:28
Have to look into most at some point, seems interesting in any case
Kirill Rogovoy
@kirillrogovoy
Feb 01 2017 15:32

@ram-bot @Avaq @stuf

R.pipeP isn't what I'm looking for because I want to mix both synchronous and asynchronous functions in the same pipe.
Like this: pipe(x => x + 1, x => Promise.resolve(x - 2), x => x * 2)(4) // returns Promise({ 6 })

I also don't want to include any additional overhead such as streams and stay as pragmatic and robust as possible.

Maybe my little project is indeed what fits the best? :) It'd be great if pipeP was more flexible!

Denis Stoyanov
@xgrommx
Feb 01 2017 15:32

https://github.com/kirillrogovoy/promised-pipe -> kleisli + reduce
promise sequence -> traverse

We need to learn approaches! Your local solution not good

@kirillrogovoy ugly idea
Stefan Rimaila
@stuf
Feb 01 2017 15:33
While we're on the not-strictly-ramda -discussion, throwing this thought out there. Working on a project in Electron atm, and I'm wondering if other people here have done, and possibly how, managing IO for it. IO in the arbitrary sense as in not considering e.g. DOM input and console, but for other effectful things like saving to/reading from disk.
Basically user performs some action which requires IO for saving something to disk, and not wanting to end up with lots of spaghetti in the code. :D
Denis Stoyanov
@xgrommx
Feb 01 2017 15:36
People! please stop it! Traversable instead this b... https://github.com/russiann/promise-sequential
Aldwin Vlasblom
@Avaq
Feb 01 2017 15:45
If I understand correctly, what @xgrommx is trying to say, is that it's quite wasteful to create abstractions such as promised-pipe and promise-sequential while those abstractions have long existed in the form of Kleisli Composition and Traversable respectively. Promise and now Observables have us all creating these same abstractions over and over because they somehow all want to diverge their APIs and make it impossible to use existing abstractions. The "pragmatic" approach would really be to fix Promises and Streams, rather than fixing their abstractions all the time.
Rick Medina
@rickmed
Feb 01 2017 15:55
^^^
Kirill Rogovoy
@kirillrogovoy
Feb 01 2017 15:59

@xgrommx @Avaq Ok, is there a solid solution for my problem which doesn't involve the whole Fantasy Land? My point is I use FP in JS in a very pragmatic fashion and I don't want to force my collaborators to dig into such stuff to much. I want JS to still be JS, not Haskell and if JS gives me promises as a native way to deal with async code then I'd probably use them as long as they fits the task. And promises do solve their task in a good way.

Also, could you, please point out where I can start to solve my problem the way you suggest, so I can get some expertise at it? I'm looking for a complete JS solution built on the principles you described.

Anyway, thanks for your replies! :)

Juan Lulkin
@joaomilho
Feb 01 2017 16:06
@Bravilogy haha, I thought you were already using folktake. From where is this Task type?
Rick Medina
@rickmed
Feb 01 2017 16:06
if you want to stick with promises why don't use promise.all or ramda's pipeP? If you want to cross to the other side (which I highly recommend) I would point you to https://egghead.io/courses/professor-frisby-introduces-function-composition :)
Bravi
@Bravilogy
Feb 01 2017 16:06
@joaomilho I am, but not all of its features :D
Juan Lulkin
@joaomilho
Feb 01 2017 16:06
ah
Rick Medina
@rickmed
Feb 01 2017 16:07
@kirillrogovoy
Juan Lulkin
@joaomilho
Feb 01 2017 16:07
well, I assume fromPromise should be fromPromise(axios.get('URL')) and that's it
you just have to wrap that Task into Async I assume, like in the docs
but again, this is version 1 :/
I'm not sure how it works in v2, seems a little incipient
Bravi
@Bravilogy
Feb 01 2017 16:09
@joaomilho but that's not related to my lenses issue, right? actually I sorted that out already anyway but still
there are so many libraries for monads like monet, folktale and etc
never know which one to go for :D
ramda-fantasy too
Aldwin Vlasblom
@Avaq
Feb 01 2017 16:12

@kirillrogovoy

Ok, is there a solid solution for my problem which doesn't involve the whole Fantasy Land?
I want to mix both synchronous and asynchronous functions

It seems you have already solved your problem in the way you deemed fitting. Composing functions with different output types using an abstraction that makes decisions based on the output type goes somewhat against the functional way, and I think therefore we cannot provide you a solution from our world.

please point out where I can start to solve my problem the way you suggest

I can tell you about my personal path: The first thing I did when I learned about the Functional Programming principles is do away with Promises. Initially I used Ramda-Fantasy Futures and it was such a pleasant experience compared to Promises that I decided never to go back. Soon the weaknesses of using libraries that were ported from strongly typed languages began to show in the form of errors like: g is not a function, and that's when I set out to create Fluture, with strong runtime type-checking, informative error messages, yet high performance.

I'm looking for a complete JS solution built on the principles you described

This sounds like you might be looking for an initiative like Folktale or something less involved in architecture; Sanctuary

Kirill Rogovoy
@kirillrogovoy
Feb 01 2017 16:12
@rickmed As I mentioned above, pipeP doesn't fit since I need to compose both synchronous and asynchronous functions. pipeP assumes every function in the chain returns a promise.
Rick Medina
@rickmed
Feb 01 2017 16:25
@kirillrogovoy right, what you want is chain/map which promises don't have (which interestingly was one of (the main?) causes motivating fantasy-land while discussing the promise A+ spec ). In your example your only options (imo) are to wrap your functions in promises to pipep or don't use pipe and use .then subsequently (which would be the same thing without using pipe) (or cross to the other side and use the tasty chain/map + many many other things :))
Aldwin Vlasblom
@Avaq
Feb 01 2017 16:30
To illustrate how your problem might be solved if Promises would have chain and map not merged into a single function:
//    f :: a -> Future b c
const f = R.pipe(
  sync1,
  async1,
  map(sync2),
  chain(async2),
  chain(async3),
  map(sync3)
)
Kirill Rogovoy
@kirillrogovoy
Feb 01 2017 16:30

@Avaq Guess you have the point. My solution is pretty much ok as long as I don't call it a FP way. :) And there is no way to do the same without moving along with deeper FP concepts. Thanks for the clarification!

@Avaq @rickmed I just feel like there is a line after which it doesn't make sense to use FP in JS because there's nothing left from JS and it's easier to move on to another, FP-based language. And for me this line lays before you no longer use most of built-in types and language conceptions. I like JS and want to still code in JS, but I find many of FP stuff a lot more efficient. Ramda itself was an enlightenment for me as I enjoyed just converting my imperative code to FP-like. But I'm not sure I'm ready to move forward with FP in JS and now I believe it only will hurt my products and my collaborators.

If I'll decide to give myself in to the true FP, I guess I will start with another language.

BTW, does it make sense to look into RxJS?

Rick Medina
@rickmed
Feb 01 2017 16:37
@kirillrogovoy you have answered yourself :) (but honestly, If I were you I would just try replacing promises with Tasks/Futures and decide from there). Re: rxjs. No. rxjs is much more complicated than futures and way an overkill for your problem at hand (it solves other problems)
Brad Compton (he/him)
@Bradcomp
Feb 01 2017 16:42
@kirillrogovoy I've used a then helper with pipe/compose before:
const then = (f) => (p) => p.then(f);

pipe(
    sync,
    then(async),
    then(async)
)
Kirill Rogovoy
@kirillrogovoy
Feb 01 2017 16:45
@rickmed Is there a way to start using Tasks/Futures without involving lots of Fantasy Land stuff? I do want to find the best and at least a right solution for this in terms of FP. :)
Rick Medina
@rickmed
Feb 01 2017 16:47
sure, they are actually not that different from promises. This explains it fairly well https://github.com/rpominov/fun-task
I'll give you the crash course. There are two main differences. .then is split into map (for sync stuff) and chain (async when returning another future), and it is lazy (need to call .run/fork to run it). that's basically it :)
Rick Medina
@rickmed
Feb 01 2017 16:55
@kirillrogovoy
Rick Medina
@rickmed
Feb 01 2017 17:03
brad's solution is a good one! Also, there's no need to write everything point free, if you have a chain of promise returning functions, just have a normal function (no pipe) and do .then (sync or async) all the way down, ramda's curried functions play nicely with that style as well
Juan Lulkin
@joaomilho
Feb 01 2017 17:46
@Bradcomp I suppose this is what invoker is for
like in
const then = invoker(1, 'then')
pipe(
  fetch,
  then(p => p.json()),
  then(console.log)
)('http://jsonplaceholder.typicode.com/posts')
Juan Lulkin
@joaomilho
Feb 01 2017 17:52
or abusing it
const then = invoker(1, 'then')
const json = invoker(0, 'json')
pipe(
  fetch,
  then(json),
  then(console.log)
)('http://jsonplaceholder.typicode.com/posts')
Richard Van Camp
@RikuVan
Feb 01 2017 21:02
This really bit me in an app I am working on: https://goo.gl/Im1RLe. Where the does isPerson go and why? Oddly it doesn't happen if you don't assign the R.merge(...) to a variable. Is this a bug in Ramda?
Kirill Rogovoy
@kirillrogovoy
Feb 01 2017 21:43

@rickmed I took a look at Tasks and Futures.
The problem with the Tasks is that the main difference from the Promises is that you can control the state of the action you're performing and I can't see how it can help with my issue since the issue is only related to the process of retrieving the result.

Futures are much more interesting and it'd take a while for me to gasp the whole concept because I intentionally avoided learning the Fantasy Land so far. :) Thank you for your suggestion.

My current thought is that I should either keep avoiding the FL and stick to more JS ways of doing things or to take a leap of fate and dive deep into the FL as I did with basic FP concepts some time ago.

Rick Medina
@rickmed
Feb 01 2017 22:07
@kirillrogovoy that's interesting. Futures and Tasks are very similar (they differ in a few capabilities here and there) but the main api you would need chain/map is identical in both (with conforms to FL spec). 2) I think you are looking at it too extremely, there is no need to dive deep or not at all. For your original (simple) problem, just use one of the examples suggested above really, tasks won't give you a significant advantage imo -until an error gets swallowed when you forget a .catch, need to cancel or retry/reuse a computation, etc.... Also, you don't need to "learn FL" in order to subsequently apply fp bit by bit.