These are chat archives for ramda/ramda

13th
Dec 2015
Aldwin Vlasblom
@Avaq
Dec 13 2015 00:18 UTC
I did a small review sweep of the code; http://goo.gl/uyFGIF, didn't really solve the two-traversals thing, it's difficult since one traversal is recursive and the other isn't. But my comments might be helpful.
Off to bed now, see you.
Tobias Pflug
@gilligan
Dec 13 2015 09:54 UTC
@Avaq thanks!
Aldwin Vlasblom
@Avaq
Dec 13 2015 15:48 UTC
I want to learn about type transformers, like ReaderT. Can somebody give me a brief explanation, example or resource so I can get started? What is their purpose? Is there a benefit to using a ReaderTFuture over a Reader[Future]? I played a bit and can achieve the same with both (though the ReaderT is more convenient): http://goo.gl/J2J9lS. Am I even using it right? Is it merely a convenience?
Scott Sauyet
@CrossEye
Dec 13 2015 15:52 UTC
Sorry, Avaq, still haven't spent any time with them.

Thinking about #1543, I became puzzled by something, and I was wondering if anyone has any insight:

Because it's easy to work with, many of our examples of lift use add, so me might define mAdd = lift(add). Well add is a straightforward function, and it happens to be commutative, add(a, b) ≡ add(b, a). It simply seemed obvious that mAdd would also be commutative. In simple cases, it is:

mAdd(Maybe.Just(10), Maybe.Just(32)); //=> Maybe.Just(42)
mAdd(Maybe.Just(32), Maybe.Just(10)); //=> Maybe.Just(42)

But it's definitely not:

R.lift(R.add)(Either.Right(10), Either.Left('oops')); //=> Either.Left('oops')
R.lift(R.add)(Either.Left('oops'), Either.Right(10)); //=> Either.Right(10)

My question is: Is my intuition leading me astray? Or should we expect that if fn is commutative, then lift(fn) is also commutative? If so, is there something wrong with lift or one of its dependencies? Or is there something the matter with Either?


Never mind. It clearly cannot be commutative:

R.lift(R.add)(Either.Left('oops'), Either.Left('a-daisy'));

So my intuition is off.

Tobias Pflug
@gilligan
Dec 13 2015 16:00 UTC
@Avaq "type transformer" ? Well you mean monad transformer right?
Aldwin Vlasblom
@Avaq
Dec 13 2015 16:01 UTC
Yeah
Is it only doable with Monads though?
Why not all Functors?
Wasn't certain about that either, so I said "type" to stay generic. :)
Aldwin Vlasblom
@Avaq
Dec 13 2015 16:07 UTC
But now, knowing that it's just for Monads, I find more info on the internet :)
Still not sure where I'd use them though. :\
Tobias Pflug
@gilligan
Dec 13 2015 16:09 UTC
I can prolly give you some links later
For use with JS? I would not care
For Haskell: certainly
Aldwin Vlasblom
@Avaq
Dec 13 2015 16:11 UTC
Haha, I see. I only just started with FP a few months ago in JS, so I wouldn't know. :)
Tobias Pflug
@gilligan
Dec 13 2015 16:12 UTC
If you want to do IO but also be able to- say encode errors with Either or Maybe you want to reach for a transformer so you can stack those monads
Haskell tho
Aldwin Vlasblom
@Avaq
Dec 13 2015 16:27 UTC
Cool, thanks @gilligan, I'm sure I'll find my way around the Haskell examples.
Hardy Jones
@joneshf
Dec 13 2015 17:21 UTC
@CrossEye Assuming lift doesn't do any kind of reflection or something, that Either you're using looks broken.
@CrossEye that is to say, it only uses ap, map and friends.
@Avaq it's only necessary with Monads, well more accurately it's only necessary with Chains. Really they should be called Chain Transformers, or Bind Transformers, or whatever the language uses.
but since not all languages/libraries distinguish between Monad and Chain/Bind, they have the name they have.
@Avaq the reason they are necessary is that the composition of two Chains is not necessarily another Chain.
If you take any two Functors, and compose them, the result is always a Functor.
same with Applys, and Applicatives.
Hardy Jones
@joneshf
Dec 13 2015 17:26 UTC
What this means is that you could create a Composition data type that encoded this logic. Give it two composable data types, and you get Functor, Apply, Applicative behavior for free.
Tobias Pflug
@gilligan
Dec 13 2015 17:37 UTC
Functor Composition would be a natural Transformation - right?
@joneshf actually- which langs /do/ differentiate between Monad/Chain ? Fantasyspec was the first time I saw that distinction
Hardy Jones
@joneshf
Dec 13 2015 17:43 UTC
// We can compose any two `Functor`s `x` and `y`
const Comp = x => ({
  map: f => x.map(y => y.map(f)),
  toString: () => x.map(y => y.toString()).toString(),
});

const None = {
  map: _ => None,
  toString: () => 'None',
};

const Some = x => ({
  map: f => Some(f(x)),
  toString: () => `Some(${x})`,
});

const Left = x => ({
  map: _ => Left(x),
  toString: () => `Left(${x})`,
});

const Right = x => ({
  map: f => Right(f(x)),
  toString: () => `Right(${x})`,
});

const someRight = Comp(Some(Right(3)));
console.log(`${someRight.map(x => x + 1)}`); //=> Some(Right(4))

const someLeft = Comp(Some(Left(3)));
console.log(`${someLeft.map(x => x + 1)}`); //=> Some(Left(3))

const noneRight = Comp(None);
console.log(`${noneRight.map(x => x + 1)}`); //=> None
quick example.
so you only have to map once, rather than going down in there multiple times.
And if you have 3, 4, 5, etc types you're composing, well, you just keep on Composing.
and still you only map once.
It extends to ap and of as well.
But chain doesn't work.
so you need an explicit way to chain two data types.
Actually, I'm not sure if all data types can have a transformer version.
Hardy Jones
@joneshf
Dec 13 2015 17:48 UTC
@gilligan purescript, scalaz, there are libs in hackage as well.
well, languages and libraries.
fantasy-land as you pointed out.
Extending the example above:

const Id = x => ({
  map: f => Id(f(x)),
  toString: () => `Id(${x})`,
});

const nested = Comp(Some(Comp(Id(Comp(Right(Comp(Some(Some(3)))))))));
console.log(`${nested.map(x => x + 1)}`); //=> Some(Id(Right(Some(Some(4)))))
Of course, you probably want to toString to tell you it's a Comp at each level.
Hardy Jones
@joneshf
Dec 13 2015 17:54 UTC
but it's just a quick example :)
The creation is pretty ugly right there, but since Applicatives compose, you could factor all that out similar to how ramda does compose/pipe. and just use of a whole bunch of times.
Hardy Jones
@joneshf
Dec 13 2015 18:02 UTC
Also, bear in mind, these are not the only things that do compose, most of the fantasy-land algebras compose.
So long as their constituents compose.
also you might need to have it be a Functor or something.
like I did with toString up there.
But you can do similarly for Setoid, and have equality for free, if the two base data types are Functor and Setoid, for example.
Aldwin Vlasblom
@Avaq
Dec 13 2015 19:34 UTC

That's awesome @joneshf, thanks for clearing a bunch of stuff up! :)
So Monad Transformers are a ways for a Chain to say: "Here's how you can compose my chain."
And that fills in the missing gap of monadic behaviours which are otherwise all composable?
And the reason you'd want to compose Monads is the same as for why you'd want to compose any other bits of code - to keep "dry"?
So it really is mainly a convenience for not having to mapmapmap over your nested containers?

I should get more accustomed with the theory behind monads, and the laws they follow. I've been learning to use them, in the API-sense, but I've yet yo fully understand them.

Hardy Jones
@joneshf
Dec 13 2015 19:43 UTC
yeah, that's pretty much it.
But I can tell you you're not that far off from fully understanding things if you're using them regularly. Once you get the laws, that's all there is to it. There's no magic stuff, or special casing, or any of that stuff. Just functions and a few laws. It might seem like you're missing something, but that's just hype.
Xananax
@Xananax
Dec 13 2015 21:51 UTC
Hello, I'm just back from reading the whole thread at ramda/ramda#1073 (and ramda/ramda#1130) about deep merge, and I'm a bit stumped. I've become more and more fanatic about functional programming (for practical reasons, it's really helping me being organized), but I'm having a bit of trouble perusing the ramda docs (lots of terms/notations that are not - yet - very familiar to me). My question is: how do I deep merge?
I realize I can do a map(function operate(val){if(isObject(val)){return map(operate,val)};return val},obj), but is there a more elegant or Ramda-idiomatic way?
Xananax
@Xananax
Dec 13 2015 21:57 UTC
Uh, actually, sorry, not map...Is there an equivalent to merge that takes a transform function?
David Chambers
@davidchambers
Dec 13 2015 22:00 UTC
I'm not sure it's possible to write "deep merge" and "elegant" in the same sentence. ;)
Xananax
@Xananax
Dec 13 2015 22:00 UTC
Provided I'm certain I don't have cyclic references, functions, or arrays
I know where my data is coming from, I just want to reduce a bunch of objects into one, merging objects, but overwriting all other values
Xananax
@Xananax
Dec 13 2015 22:13 UTC
Wait, isn't set doing deep merging?
Xananax
@Xananax
Dec 13 2015 22:24 UTC
Ah no, it's in a PR not yet merged...Too bad, because if it was it seems to me I could do (...objs)=>reduce(set,{},objs), which is elegant enough imho
Scott Christopher
@scott-christopher
Dec 13 2015 22:55 UTC
@Xananax :point_up: November 24, 2015 12:36 PM
Scott Sauyet
@CrossEye
Dec 13 2015 23:01 UTC
@joneshf: Are you suggesting, though, that lift(fn) should be commutative if fn is? I haven't tried this with other versions of Either for comparison. Perhaps I'll do that later.
Xananax
@Xananax
Dec 13 2015 23:07 UTC
@scott-christopher but this is not released on npm yet, is it? Cool nonetheless
Scott Christopher
@scott-christopher
Dec 13 2015 23:07 UTC
Correct, however I believe we're overdue for a new release.
Xananax
@Xananax
Dec 13 2015 23:10 UTC
I'll npm from github in the meantime
This library is really great, but documentation/examples, follow up on changes and so on, are thoroughly lacking. I've spent three hours doing what I would've done in 10 if I wrote the functions myself...But I'm learning. I'd love to participate, but I'm a bit of a noob. Anything I can do from the modest pedestal of my modest knowledge?
Scott Christopher
@scott-christopher
Dec 13 2015 23:23 UTC
Has anyone had any issues like this of modules not being able to be required with Node?
~/foo ❯❯❯ npm install ramda
/Users/Scott/foo
└── ramda@0.18.0 
~/foo ❯❯❯ ls node_modules/ramda
BOOKMARKLET.md CHANGELOG.md   LICENSE.txt    README.md      dist           package.json   src
~/foo ❯❯❯ node
> var R = require('ramda');
Error: Cannot find module 'ramda'
    at Function.Module._resolveFilename (module.js:327:15)
    at Function.Module._load (module.js:278:25)
    at Module.require (module.js:355:17)
    at require (internal/module.js:13:17)
    at repl:1:9
    at REPLServer.defaultEval (repl.js:252:27)
    at bound (domain.js:281:14)
    at REPLServer.runBound [as eval] (domain.js:294:12)
    at REPLServer.<anonymous> (repl.js:417:12)
    at emitOne (events.js:83:20)
Running Node v5.2 on OS X
Xananax
@Xananax
Dec 13 2015 23:27 UTC
If it helps, I get the same behavior on Arch Linux, running also node 5.2. Works if I do require('./node_modules/X') though
Scott Christopher
@scott-christopher
Dec 13 2015 23:28 UTC
:(
Xananax
@Xananax
Dec 13 2015 23:28 UTC
Has it ever worked? I never tried requiring from the REPL
Scott Christopher
@scott-christopher
Dec 13 2015 23:29 UTC
Yeah, I'm sure it was working fine on v5.0
Xananax
@Xananax
Dec 13 2015 23:32 UTC
I'd wager your ~/node_modules is not in your npm path
It's not the normal place for globally installed modules
You can do export NODE_DEBUG=module then when you start the repl and require, it will print your paths
Scott Christopher
@scott-christopher
Dec 13 2015 23:34 UTC
The repl used to include the node_modules directory in your CWD
Xananax
@Xananax
Dec 13 2015 23:34 UTC
~/p/react-tmpl git:master ❯❯❯ export NODE_DEBUG=module                  ✖ ✱ ◼
~/p/react-tmpl git:master ❯❯❯ node                                           ✖ ✱ ◼
> var R = require('ramda')
MODULE 29674: Module._load REQUEST ramda parent: <repl>
MODULE 29674: looking for "ramda" in ["/home/xananax/.node_modules","/home/xananax/.node_libraries","/usr/lib/node"]
Scott Christopher
@scott-christopher
Dec 13 2015 23:42 UTC
No idea. Just confirmed it works in v5.1
Might have to just ride it out on that version for a while.
Xananax
@Xananax
Dec 13 2015 23:43 UTC
I think you can just add the path to your npm configuration
Scott Christopher
@scott-christopher
Dec 13 2015 23:51 UTC
Ah, just discovered nodejs/node#4208
Xananax
@Xananax
Dec 13 2015 23:53 UTC
Ah, nice. It was bugging me too, just out of curiosity
Scott Christopher
@scott-christopher
Dec 13 2015 23:57 UTC
The NODE_DEBUG=module env var is a handy trick to know.
Xananax
@Xananax
Dec 13 2015 23:58 UTC
Yeah I had no idea either, got that by doing a bit of googling about your problem
But I'm curious, I find it interesting that you're willing to downgrade to use the REPL, do you use it so much?
Scott Christopher
@scott-christopher
Dec 13 2015 23:59 UTC
I tend to use it when I just want to test something quickly