These are chat archives for ramda/ramda

30th
Apr 2018
Dmitri Zaitsev
@dmitriz
Apr 30 2018 06:49
Hi folks, I'm trying to rewrite this Binance crypto-trading API library https://github.com/zoeyg/binance/blob/master/lib/ws.js#L25
in some more functional style...
The use case seems to be very common - prepare url, run 3rd party API, then transform the response
Here is the function to prepare url:
const BASE_URL = 'wss://stream.binance.com:9443/ws/'

const getUrl = (type, symbol) => [
  BASE_URL, 
  symbol.toLowerCase(),
  `@`,
  type
].join('')
Next, this one to get WebSocket Stream:
const WebSocket = require('ws')
const createWSStream = (path, cb) => {
  const ws = new WebSocket(path)
  ws.on('message', msg => cb(msg))
  return ws
}
And then just use JSON. parse to apply to result
My question is how to implement this pipeline with ramda?
Here is my attempt:
const getStream = pipe
(
  getUrl
, curry(createWSStream) // returns f: cb -> void
// takes cb-accepting fn and transforms the output before cb
, cbFn => cb => cbFn(compose(cb, JSON.parse))
)

getStream('trade', 'BNBBTC')(console.log)
Dmitri Zaitsev
@dmitriz
Apr 30 2018 06:55
The last function feels somewhat heavy, so I wonder if there is any better way
It should be a general purpose transformation, taking a callback-based function and transforming the output before the callback.
Something like preCompose(JSON.parse) perhaps?
That would take any function and pre-compose with JSON.parse
Tomáš Konrády
@tommmyy
Apr 30 2018 11:21
Noah Swanson
@lummo0
Apr 30 2018 11:22
There is any way to make something like f(x) => a(x)&&b(x)...&&n(x) with ramda?
Tomáš Konrády
@tommmyy
Apr 30 2018 11:23
Noah Swanson
@lummo0
Apr 30 2018 11:25
Oh never thought of that, thanks!
Dmitri Zaitsev
@dmitriz
Apr 30 2018 11:26
@tommmyy Thank you! But why is
cbFn(compose(cb, JSON.parse))the same as compose(cbFn, cb, JSON.parse)?
In the first case, cbFn is applied to the composite function, in the second it is applied to the value returned by that function?
Tomáš Konrády
@tommmyy
Apr 30 2018 11:30
@dmitriz i am sorry, you are right
Noah Swanson
@lummo0
Apr 30 2018 11:48
s
Dmitri Zaitsev
@dmitriz
Apr 30 2018 11:48

After some thoughts, perhaps this should be generalized to

// Functor structure on CPS functions
const cpsMap = f => cpsFn => 
  // new CPS function
  cb => cpsFn(compose(cb, f))

Does it occur anywhere in Ramda?

Brad Compton (he/him)
@Bradcomp
Apr 30 2018 16:01
@dmitriz Check out the continuation monad. It encapsulates the sort of thing you're talking about.
Adam Dawkins
@adamdawkins
Apr 30 2018 20:00

Hi, I was pretty thrown by the ordering of R.gt just now. I partially applied it in an R.cond e.g.

const statusCodeToStatus = cond([
[R.gt(399),   R.always('ERROR')],
...
])

I was able to fix it with gt(__, 399), but it really does feel like it's the wrong way round, that with partial application the last argument should always be the true value of teh name

Feel like I'd really expect to make greaterThan500 = R.gt(500) - but, that's actually created the opposite, it's created a 'true if less than 500'
Ben Briggs
@ben-eb
Apr 30 2018 20:07
That's caught me out before too :)
Brad Compton (he/him)
@Bradcomp
Apr 30 2018 20:10
Here is the canonical discussion on the topic: ramda/ramda#1497
Adam Dawkins
@adamdawkins
Apr 30 2018 20:16
canonical gets a +1 from me
I'll have a read,
freaked me out lol
Brad Compton (he/him)
@Bradcomp
Apr 30 2018 20:19
The short answer is that it's a hard issue to get consensus on :stuck_out_tongue:
Ben Briggs
@ben-eb
Apr 30 2018 20:19
@Bradcomp Indeed, thanks for the link :)
Adam Dawkins
@adamdawkins
Apr 30 2018 20:20
Lol, yes, I got that vibe half way through. It seems that everyone agrees that greaterThanFive = gt(5); greaterThanFive(6) // false is terrible, but changing it would be at the expense of consistency with other functions.
hey ho, I got round it with __, just had a moment where I thought I'd forgotten how to count
Ben Briggs
@ben-eb
Apr 30 2018 20:22
The way it is now makes sense if you think of it as gte(5, 6) === 5 > 6
Adam Dawkins
@adamdawkins
Apr 30 2018 20:23
yea, I know, that does make sense, it's just that I'm only using it because it's partially applied, if I knew both numbers I'd do 5 > 6
I just get used to partially applied functions taking the last argument as the 'thing to apply it to'
Ben Briggs
@ben-eb
Apr 30 2018 20:23
Or you can think of the function as taking the 5 > and waiting for the 6
Adam Dawkins
@adamdawkins
Apr 30 2018 20:24
it's weird that gt(5) on it's own actually means 'less than 5', but I understand most of the thorough discussion going on, so I'll just remember it.
@ben-eb Ok, that works, maybe... probably having this chat will help me remember enough!
Ben Briggs
@ben-eb
Apr 30 2018 20:25
And me! :)