These are chat archives for ramda/ramda

13th
Mar 2016
Nathan Ridley
@axefrog
Mar 13 2016 01:13
To what extent do you guys go pointfree?
Scott Sauyet
@CrossEye
Mar 13 2016 01:17
I prefer points-free to pointed code, but only when it makes what I'm doing more clear. For a long time that was commonly the case, but in the days of ES6 with its fat-arrow syntax, it's becoming more and more common for me to use simple pointed functions, even in the middle of an otherwise points-free pipeline.
Nathan Ridley
@axefrog
Mar 13 2016 01:46
@CrossEye Sorry for the slow reply, was on the phone... But yeah I've been trying to figure out how deep to go with point-free style. It seems once you start getting down to the micro level (composing an object, etc.) point-free code starts to get less efficient and less readable than simply writing simple arrow functions that return a value or do a calculation.
Nathan Ridley
@axefrog
Mar 13 2016 02:31

Question:

var isMinLength = R.compose(R.gte(R.__), R.length);

How do I reformat that so I can get back a function for a specific length, i.e. isMinLength(20) and then feed that a string to test?

Right now it only works in reverse, i.e. isMinLength('foobar')(20)
Raine Virta
@raine
Mar 13 2016 03:08
@ram-bot:
isMinLength = flip(useWith(gte, [ length, identity ]))
isMinLength(4, 'foo')
ram-bot
@ram-bot
Mar 13 2016 03:08
false
Raine Virta
@raine
Mar 13 2016 03:10
but yeah, isMinLength = curry((n, str) => str.length >= n) is more readable
Nathan Ridley
@axefrog
Mar 13 2016 03:12
ok, so flip would actually be required in that case
i avoided flip because i thought i was perhaps cheating
thanks @raine
Raine Virta
@raine
Mar 13 2016 03:13
flip is not cheating
Nathan Ridley
@axefrog
Mar 13 2016 03:14
i meant cheating as in working around an incorrect solution to correct it, rather than just doing it right to begin with
Risto Stevcev
@Risto-Stevcev
Mar 13 2016 04:02
@axefrog Yeah I agree that it can get hard to read or write type signatures for functional JS. In Haskell you at least have :type to help you determine or discover types. There's no JS equivalent. Plus there's no tuples so that sig was super confusing.
And saying [a, b] isn't any clearer, since [a] is generally used for a generic array
Though at the same time the type signatures demonstrate the power of that style of programming, since it shows that you can partially apply the function at each -> step, and create a domain specific language for your app using generic but powerful functions
Maybe it would be possible to work on creating something like the Haskell :type? I wonder how difficult that would be.
Probably pretty hard
Scott Sauyet
@CrossEye
Mar 13 2016 04:10
This message was deleted
@ram-bot:
isMinLength = useWith(lte, [identity, length]);
isMinLength(4, 'foo');
hmm
In any case, why the flip, gte? Why not just lte?
Risto Stevcev
@Risto-Stevcev
Mar 13 2016 04:40
Not sure if this counts as cheating
@ram-bot
var isMinLength = R.curry((length, a) => R.compose(R.gte(R.__, length), R.length)(a))
isMinLength(4, 'foo')
ram-bot
@ram-bot
Mar 13 2016 04:40
false
Risto Stevcev
@Risto-Stevcev
Mar 13 2016 04:40
Though flip is nicer
James Forbes
@JAForbes
Mar 13 2016 04:58
I remember someone asking this a few days ago, but is there a nice way to alter the keys of an object. I'm imagining something like R.evolve
R.evolveKeys({
   Make: 'photo_make',
   Aperture: 'photo_aperture'
})
David Chambers
@davidchambers
Mar 13 2016 07:52
I can see that being useful, @JAForbes. I like the name R.rekey.
James Forbes
@JAForbes
Mar 13 2016 09:16
@davidchambers should it traverse or just be top level do you think?
David Chambers
@davidchambers
Mar 13 2016 09:24
Just top level, I would say.
James Forbes
@JAForbes
Mar 13 2016 09:24
I agree, if rekey is the name, top level is less suprising
Hardy Jones
@joneshf
Mar 13 2016 12:16
@axefrog as @raine stated, the pointful version is much more understandable. And that sort of answers your own question :). If you are confused writing something pointfree, it probably shouldn't be pointfree.
Hardy Jones
@joneshf
Mar 13 2016 12:21
I guess more generally, if the point is more than one function deep, or you have to flip more than once, it's questionable whether you should do it. The more points that have these sorts of issues, the less likely you should write it pointfree.
David Chambers
@davidchambers
Mar 13 2016 20:18
@ram-bot
R.ap(S.Just(S.parseInt(10)), S.Just('42'))
ram-bot
@ram-bot
Mar 13 2016 20:18
Just(Just(42))
David Chambers
@davidchambers
Mar 13 2016 20:19
Is there a way to avoid this extra nesting, or is applying R.unnest to the result the best approach?
Denys Mikhalenko
@prontiol
Mar 13 2016 20:26
sorry for offtopic but what's Just?
David Chambers
@davidchambers
Mar 13 2016 20:26
Denys Mikhalenko
@prontiol
Mar 13 2016 20:29
well, i mean, is it defined in ramda or other library? i've seen some references to Just and Maybe in ramda docs, but never seen it defined anywhere
David Chambers
@davidchambers
Mar 13 2016 20:30
The Maybe type provides a way to encode the possibility of failure in a value, so we don't need to resort to exceptions. Several libraries provide implementations of this type: Folktale, ramda-fantasy, and Sanctuary (among others).
Denys Mikhalenko
@prontiol
Mar 13 2016 20:31
ah okay, thanks
Roman Pominov
@rpominov
Mar 13 2016 20:58
@davidchambers hm, that doesn't seem right. ap shouldn't add extra nesting
how R.ap works btw? Does it delegate to Just(...).ap?
if so, Just(...).ap seems broken
Roman Pominov
@rpominov
Mar 13 2016 21:04
ah, i see parseInt also returns Maybe
David Chambers
@davidchambers
Mar 13 2016 21:05
As it should. ;)
Jakub Korzeniowski
@kujon
Mar 13 2016 21:06
@davidchambers why would you have S.parseInt(10) wrapped with S.Just?
Raine Virta
@raine
Mar 13 2016 21:06
S.Just('42').chain(S.parseInt(10))?
Roman Pominov
@rpominov
Mar 13 2016 21:06
yep, so all works as expected. I don't know how this nesting can be avoided, but you can use .chain(x => x) to remove it afterwards
or does R.unnest use chain under the hood?
David Chambers
@davidchambers
Mar 13 2016 21:08
R.unnest is defined as R.chain(R.identity).
Roman Pominov
@rpominov
Mar 13 2016 21:08
ah, cool
actually, I think the right way to do it is S.Just('42').chain(S.parseInt(10))
David Chambers
@davidchambers
Mar 13 2016 21:09
@raine, in this case I have something like S.Just(S.parseInt(10)), as the value is the result of applying a function whose type is as follows:
customize :: String -> Either String (String -> Either String String)
I don't have S.parseInt(10), I really do have something like S.Just(S.parseInt(10)). ;)
Roman Pominov
@rpominov
Mar 13 2016 21:10
@ram-bot
R.chain(S.parseInt(10), S.Just('42'))
ram-bot
@ram-bot
Mar 13 2016 21:10
Just(42)
David Chambers
@davidchambers
Mar 13 2016 21:12
Here's the actual code, in case you're interested.
Roman Pominov
@rpominov
Mar 13 2016 21:16
Yeah, I don't see a better way than ap+unnest then :(
David Chambers
@davidchambers
Mar 13 2016 21:16
No worries. That doesn't seem too bad to me.
Aldwin Vlasblom
@Avaq
Mar 13 2016 21:34

@davidchambers I have the same issue a lot when I use Future#ap for parallelism:

Future.of(a => b => asyncDoStuff(a, b)) //asyncDoStuff returns another Future
.ap(Future.of('a'))
.ap(Future.of('b')) //the two aps run in parallel
.chain(identity) //I now have to unnest, meh

It seems fiddly to have to unnest. I haven't found a more elegant way though.

Roman Pominov
@rpominov
Mar 13 2016 21:37
@davidchambers just curious, what [$.String, Either($.String, $.String)] is for? runtime type checking?
Roman Pominov
@rpominov
Mar 13 2016 21:54
@Avaq not sure if it any better but should work
R.sequence(Future.of, [Future.of('a'), Future.of('b')])
.chain(([a, b]) => asyncDoStuff(a, b))
If Future have something like Promise.all, it could look like this:
Future.all([Future.of('a'), Future.of('b')])
.chain(([a, b]) => asyncDoStuff(a, b))
but anyway not sure if it's better that ap+ap+chain(id)
David Chambers
@davidchambers
Mar 13 2016 21:59

just curious, what [$.String, Either($.String, $.String)] is for? runtime type checking?

That's right. I'm using sanctuary-def. It makes it much easier to get the types to line up. :)

Roman Pominov
@rpominov
Mar 13 2016 22:07
Cool, I was hopping that maybe they are used to pass type information for functions like R.sequence, where we need to specify of of the inner type. But type checking seems useful too.
David Chambers
@davidchambers
Mar 13 2016 22:09
It would be very cool if it could serve both roles!
Roman Pominov
@rpominov
Mar 13 2016 22:11
Yeah, that would be very cool!
David Chambers
@davidchambers
Mar 13 2016 22:12
@ram-bot
R.chain(S.parseInt(10), S.Just('42'))
ram-bot
@ram-bot
Mar 13 2016 22:12
Just(42)
David Chambers
@davidchambers
Mar 13 2016 22:13
@ram-bot
R.chain(S.parseInt(10), S.Right('42'))
ram-bot
@ram-bot
Mar 13 2016 22:13
TypeError: ‘Either#chain’ is expected to return a value of type (Either a c); returned Just(42)
David Chambers
@davidchambers
Mar 13 2016 22:13
There's an example of the error reporting, by the way.
Roman Pominov
@rpominov
Mar 13 2016 22:19
That probably very useful, especially on server side where debug is much harder.
I was playing with types composition recently, where I try to compose Stream with another arbitrary inner Type. Wrote a bunch of generic code, and then it just throws undefined is not a function all the time :)
Left that stuff unfinished at the end, and switched to write a lib which hopefully will help to finish that experiment
Roman Pominov
@rpominov
Mar 13 2016 22:28
Basically trying to move some code to a separate well tested lib.
Probably should try runtime type checking some time...
David Chambers
@davidchambers
Mar 13 2016 22:30
I'd love your feedback on sanctuary-def. Let me know if you decide to give it a go.
Roman Pominov
@rpominov
Mar 13 2016 22:33
:ok_hand: