These are chat archives for ramda/ramda

16th
Sep 2015
Jethro Larson
@jethrolarson
Sep 16 2015 00:33
Is the .equals method on ReaderT actually sound? https://github.com/ramda/ramda-fantasy/blob/master/src/Reader.js
Scott Christopher
@scott-christopher
Sep 16 2015 00:33
Nope, they should be removed
Jethro Larson
@jethrolarson
Sep 16 2015 00:34
Okay, that's what I suspected
Scott Christopher
@scott-christopher
Sep 16 2015 00:34
They were added initially to get the tests passing
But we've since modified the tests to allow for a custom equality function to be passed in.
And I must have missed the ReaderT when I removed it from Reader
Jethro Larson
@jethrolarson
Sep 16 2015 00:35
You know a good source for understanding ReaderT?
I miss out on so much by not understanding haskell :|
Scott Christopher
@scott-christopher
Sep 16 2015 00:38
There's a small example on the PR that introduced ReaderT.
var Reader = require('./src/Reader'),
    Future = require('./src/Future'),
    ReaderTFuture = Reader.T(Future);

var log = console.log.bind(console);

var delay = d => Future((_, done) => setTimeout(done, d));

var delayedText = ReaderTFuture.ask.chain(env => 
  ReaderTFuture.lift(delay(env.delay).map(() => env.text))
);

delayedText.run({ delay: 1000, text: 'Hello!' }).fork(log, log);
Jethro Larson
@jethrolarson
Sep 16 2015 00:43
Okay, I think I understand everything but lift.
Scott Christopher
@scott-christopher
Sep 16 2015 00:43
lift is the transformer part
So that lifts the underlying monad into the ReaderT
Jethro Larson
@jethrolarson
Sep 16 2015 00:45
I lift is just map2 basically, right?
but delay() returns a future, not a function
Scott Christopher
@scott-christopher
Sep 16 2015 00:46
In the context of transformers, lift takes an underlying monad (Future in the above example) and lifts it into the transformer monad (ReaderT in the above example)
It's a way to kinda embed monads within each other, creating a stack
So a ReaderT(Future) can be thought of as a some kind of delayed computation with access to some environment
Jethro Larson
@jethrolarson
Sep 16 2015 00:49
works as if it's pre-flattened?
Scott Christopher
@scott-christopher
Sep 16 2015 00:49
and ReaderT(Identity) is essentially Reader
Jethro Larson
@jethrolarson
Sep 16 2015 00:51
I imagine that you could have T versions of many other monads, right?
Scott Christopher
@scott-christopher
Sep 16 2015 00:52
Yep, ListT, MaybeT, StateT, WriterT, IdentityT
Jethro Larson
@jethrolarson
Sep 16 2015 00:53
hmm. Seems like there's quite a bit of code here to write the interface
David Chambers
@davidchambers
Sep 16 2015 00:53
New profile picture, @raine! I'll miss the one of you in the trendy coffee shop.
Scott Christopher
@scott-christopher
Sep 16 2015 00:53
Some of this stuff doesn't translate so nicely from other languages
The implementation of chain might help provide some insight:
  ReaderT.prototype.chain = function(f) {
    var readerT = this;
    return ReaderT(function(e) {
      var m = readerT.run(e);
      return m.chain(function(a) {
        return f(a).run(e);
      });
    });
  };
The computation in the returned ReaderT first runs the original ReaderT to get access to the inner monad. Then chain is called against the inner monad to get access to the value, which is then given to f.
Jethro Larson
@jethrolarson
Sep 16 2015 00:58
Yeah, I think I follow
Scott Christopher
@scott-christopher
Sep 16 2015 00:58
The inner monad could also be another monad transformer
and so on
Jethro Larson
@jethrolarson
Sep 16 2015 00:58
I'm trying to reimplement this stuff as methodless functions, interesting challenge
Scott Christopher
@scott-christopher
Sep 16 2015 00:58
but it gets pretty messy trying to keep track of the stack in your head.
Jethro Larson
@jethrolarson
Sep 16 2015 01:00
I started writing a lot of this tacit but I keep having to undo it because I can't keep it straight in my head :)
thank goodness for babel tho
arrow functions make this waay easier
Scott Christopher
@scott-christopher
Sep 16 2015 01:02
certainly does neaten things up
Jethro Larson
@jethrolarson
Sep 16 2015 01:03
Easier on mental RAM
makes manual currying reasonable
var add = function(a){ return function(b){ return a + b};
//or 
var add = a => b => a + b
Thanks for the guidance btw
Scott Christopher
@scott-christopher
Sep 16 2015 01:07
No worries.
Jethro Larson
@jethrolarson
Sep 16 2015 01:13
IdentityT lol
Hard to imagine a use, but I'm sure it's there in abstract
Scott Christopher
@scott-christopher
Sep 16 2015 01:15
I'm not 100% sure, but I think it's main use is to wrap some underlying monad so it can be identified as a transformer.
e.g. Something that has a MonadTrans constraint in Haskell
Raine Virta
@raine
Sep 16 2015 06:45
@davidchambers heh, I think the pic was from a coffee shop at stockholm central station
Ludwig Magnusson
@TheLudd
Sep 16 2015 07:14
@scott-christopher Is Reader.T(Identity) === Reader really true?
Will it not be like this?
Reader.of('foo').run() === 'foo'
Reader.T(Identity).of('foo').run() === Identity(foo)
Scott Christopher
@scott-christopher
Sep 16 2015 09:00
@TheLudd That's correct. If you override the run method to pull the value out of the Identity and override toString, the existing tests for Reader should pass.
Scott Christopher
@scott-christopher
Sep 16 2015 13:36
@gilligan Sorry, I only just saw your earlier message. You'll probably just have to define a sum of all the types you want to test, e.g.
jsc.forall("bool | string | number | [bool] | { a: bool }", function(sum) {
  return sum.fold(function(idx, len, value) {
    return f(value) === false;
  });
})
You can swap out the string with the following if you prefer:
jsc.sum([jsc.bool, jsc.string, jsc.number, jsc.array(jsc.bool), jsc.record({ a: jsc.bool })])
Denis Stoyanov
@xgrommx
Sep 16 2015 14:03
what is it jsc?
Raine Virta
@raine
Sep 16 2015 14:04
jsverify
Denis Stoyanov
@xgrommx
Sep 16 2015 14:04
@raine provide link)
Irakli Safareli
@safareli
Sep 16 2015 14:08
calling R.anyPass with empty array throws, i think it should just return false
R.anyPass([])
Tobias Pflug
@gilligan
Sep 16 2015 14:57
@scott-christopher thanks yet again ;]
Irakli Safareli
@safareli
Sep 16 2015 15:08
is it correct behaviour if not i'll open issue
Hardy Jones
@joneshf
Sep 16 2015 15:12

@Avaq @dtipson Re: :point_up: September 14, 2015 6:25 AM you can really answer your question on your own by looking at the laws for lenses:

  1. get with the lens, then set what you got and you have the original value you started with.
  2. set with the lens, then get with the lens and you have the new value you just set.
  3. set with the lens, then set with the lens and you have the value of what you set the second time.

They're "common sense" laws, in that they make sense if you think about them (though kind of hard to formalize initially).

Since it breaks the first two laws, it's not a lens.
Drew
@dtipson
Sep 16 2015 15:16
Right, I think the reason both of us were interested is precisely because it felt wrong. The question is is there some other more formalized structure to be had for handling that sort of case that's not just a bunch of imperative instructions. Been trying to compose together something that fits the bill without much luck so far
Hardy Jones
@joneshf
Sep 16 2015 15:22
Well, each part has a formalization.
There's the Getter, and the Setter.
so on their own, they are valid structures
you just need a type system that can differentiate between them so you don't accidentally use a Getter where a Setter is wanted or vice versa, which js cannot.
Move to purescript, and your woes can be left behind :)
You could probably think about the types involved in each side of the lens, and better answer your concerns
aka, find the abstraction you're looking for.
You could also reformulate your lens a bit.
Hardy Jones
@joneshf
Sep 16 2015 15:29
If your emailToGravatar function is invertible, you could create an isomorphism, and have a lens by derivation.
that is to say, if you can take a gravatar string, and convert it to an email address, then you have what you want.
var emailLens = R.lens(R.pipe(R.prop('gravatar'), gravatarToEmail), R.pipe(emailToGravatar, R.assoc('gravatar')))
Or something
This satisfies all three laws.
but hinges on the existence of gravatarToEmail.
Hardy Jones
@joneshf
Sep 16 2015 15:35
the object you store would be {gravatar: '987d5s69f0876af8767dsa'}, but it would appear to the outside world that you actually had the object {gravatar: '987d5s69f0876af8767dsa', email: 'foo@example.com'}
If you're worried about how that might serialize in the real world, remember that you can provide a toJSON on the prototype, then, just make it do this conversion in that function. Then you could call JSON.stringify (or if backbone/jQuery/etc or some library did that for you) and have it look like you've been dealing with POJO's the whole time.
Of course, you'd want your own object for this in particular.
Drew
@dtipson
Sep 16 2015 15:45
hmm, yeah, will have to think about this some more
Irakli Safareli
@safareli
Sep 16 2015 16:34
calling R.anyPass with empty array throws error, i think it should just return false, is it correct behaviour if not i'll open issue R.anyPass([])
Scott Sauyet
@CrossEye
Sep 16 2015 16:43
@safareli: That's definitely a bug. Of course allPass([])(...args) should always return true.
Drew
@dtipson
Sep 16 2015 17:23
@Avaq http://bit.ly/1UV9ZjI I think this fulfills my intuition that lenses could potentially be useful in tackling that use case (use two different lenses rather than mixing up a single lens, alter "over" to run set on lens1 but take its argument from the "view" of lens2), but from thinking about it, also seems like it's too specific/fragile to be a meaningful general pattern/cookbooky. getGravatar itself is likely async in the real world, right? But it's already too complex to handle variations like that in a clean way (at least in es5/6)
Aldwin Vlasblom
@Avaq
Sep 16 2015 17:39
@dtipson Thanks for your thoughts! That method does seem a bit cleaner. I'll play around with it. Oh and emailToGravatarId is not async. It's basically just getting the md5 hash of the email address after some sanitization.
Drew
@dtipson
Sep 16 2015 17:41
cool. It's basically just a minor rewrite of R.over that takes two lenses instead of one. I think the second version is a clearer order of right-to-left operation
Aldwin Vlasblom
@Avaq
Sep 16 2015 17:48
If you think of lenses as a container of a getter and a setter, then it seems a bit wasteful to use two, one for its getter and the other for its setter. But if you abstract away the getter/setter bit and think of lenses as a way to focus on part of your data structure (as other libraries, and R.lensProp do) then your function becomes a nice way to express a solution to my problem. I'm not sure about the second version, but I can see where you're coming from.
Drew
@dtipson
Sep 16 2015 17:56
yeah, actually, the second lens could just be replaced with R.prop, really, since passing along the rest of the object is irrelevant at that point
David Chambers
@davidchambers
Sep 16 2015 17:56
@safareli, R.anyPass works as I would expect: http://bit.ly/1NDm5PI.
Drew
@dtipson
Sep 16 2015 18:05

but something like

var someWeirdOp3 = (function() {
  return R.curryN(4,function over(assoc, f, prop, x) {
    return assoc(f(prop(x)),x);
  });
}());
someWeirdOp3(R.assoc('gravatar'), getGravatar, R.prop('email'))(data);

definitely works, and is simpler, but seems weirder because it doesn't look like I'd get back the whole object at the end

Scott Sauyet
@CrossEye
Sep 16 2015 19:48
@davidchambers: R.anyPass([])(42) or just R.anyPass([]) throws an error.
Tobias Pflug
@gilligan
Sep 16 2015 19:59
This message was deleted
export default (context, payload) => {
    return P.join(fetchGenericPageData(context), fetchPageData(context, payload),
        function (genericPageData, pageData) {                                                                                                                 
            return [ genericPageData, pageData ];
        }); 
};
Raine Virta
@raine
Sep 16 2015 20:02
does return P.all([ fetchGenericPageData(context), fetchPageData(context, payload) ]); do the same thing?
Tobias Pflug
@gilligan
Sep 16 2015 20:03
@raine i was about to ask if there is a more concise way to write this
@raine good question, should take a glance at bluebird ..
Raine Virta
@raine
Sep 16 2015 20:04
yeah I don't actually know if all is part of the spec. I just use bluebird everywhere
the "list function" would also help
Tobias Pflug
@gilligan
Sep 16 2015 20:06
yeah P here is also bluebird
Raine Virta
@raine
Sep 16 2015 20:06
P.join(a, b, list);
Tobias Pflug
@gilligan
Sep 16 2015 20:08
@raine ah, good suggestion. Thanks
Raine Virta
@raine
Sep 16 2015 20:16
no problem
Irakli Safareli
@safareli
Sep 16 2015 20:43
http://bit.ly/1QinSai this throws.
so they just are not curried ?
David Chambers
@davidchambers
Sep 16 2015 20:46
The problem lies in _predicateWrap.js.
Specifically Math.max.apply(Math, []) evaluates to -Infinity.
I will open a pull request to fix this.
Irakli Safareli
@safareli
Sep 16 2015 20:54
ok
and if allPass default value is true why default value of anyPass is false?
Scott Sauyet
@CrossEye
Sep 16 2015 20:59
A very similar discussion on all and any was held recently in #1380. My answer there is pretty much the same here.
In short, if allPass is false, that must mean there is one that failed, right? Which one was that if the list was empty?
John-David Dalton
@jdalton
Sep 16 2015 21:01
There's a set theory way to explain this
it's how Array#every returns true for an empty array too. I don't have the set theory jargon handy though.
Scott Sauyet
@CrossEye
Sep 16 2015 21:01
Yes, it's DeMorgan's Laws.
Or some variant of them, I suppose.
Danielle McLean
@00dani
Sep 16 2015 21:02
Vacuous truth applies too.
Scott Sauyet
@CrossEye
Sep 16 2015 21:02
yes, that was also in the comment. :smile:
John-David Dalton
@jdalton
Sep 16 2015 21:04
mdn has a bit on it
every acts like the "for all" quantifier in mathematics. In particular, for an empty array, it returns true. (It is vacuously true that all elements of the empty set satisfy any given condition.)
David Chambers
@davidchambers
Sep 16 2015 21:33
The issue with R.{all,any}Pass was fixed in ramda/ramda#1299.
Why do these functions allow the arguments to be provided along with the list of predicates? It seems like a special case to me.
David Chambers
@davidchambers
Sep 16 2015 21:39
Cool!
Scott Sauyet
@CrossEye
Sep 16 2015 21:39
@davidchambers: How quickly we forget! And we really need to get another version out there.
@raine: Very nice!
@davidchambers, it makes it feel like a normally curried Ramda function.
I don't recall if that was the reason, but at least it makes some sense.
Raine Virta
@raine
Sep 16 2015 21:48
cond doesn't give you one of those "normally curried Ramda functions" either. I remember finding it weird when playing around with it
David Chambers
@davidchambers
Sep 16 2015 21:54

The illusion is not complete:

R.anyPass([R.lt, R.equals], 2, 3);  // => true
R.anyPass([R.lt, R.equals])(2, 3);  // => true
R.anyPass([R.lt, R.equals])(2)(3);  // TypeError: boolean is not a function
R.anyPass([R.lt, R.equals], 2)(3);  // TypeError: boolean is not a function

The function pretends to do more than is possible. I'd prefer to support (preds)(2)(3) than to have a special case to allow (preds, 2, 3) (but not (preds, 2)(3)).

Tobias Pflug
@gilligan
Sep 16 2015 22:12
const func = (val) => { f('foo', val); return val; }
Scott Sauyet
@CrossEye
Sep 16 2015 22:13
I didn't look into the impl of {any, all}Pass. But you're right, that's strange. I was assuming that we were just in a buggy situation. If this is by design, our design is pretty far off.
David Chambers
@davidchambers
Sep 16 2015 22:13
I'll open a PR.
Tobias Pflug
@gilligan
Sep 16 2015 22:14
.oO( why is the syntax screwed for me.hm.) -- anyway, is there a sane pointfree version of that function ?
Scott Sauyet
@CrossEye
Sep 16 2015 22:15
@gilligan: You're just calling f for its side-effects?
Tobias Pflug
@gilligan
Sep 16 2015 22:15
@CrossEye yes
Scott Sauyet
@CrossEye
Sep 16 2015 22:16
<shudder> :smile:
Tobias Pflug
@gilligan
Sep 16 2015 22:16
i'm trying to refactor some code ...
Scott Sauyet
@CrossEye
Sep 16 2015 22:16
is f curried?
so can we call f('foo')(val)?
Just thinking, and thinking that might help.
Tobias Pflug
@gilligan
Sep 16 2015 22:17
should be. if it ain't i'll make it curried
function fetchCmsGenericData(context) {                                                                                                                        
    return P.try(callCmsGenericDataService, context)
        .then(λ (genericData) {
            context.dispatch('FETCH_GENERIC_DATA', genericData);

            return genericData;
        });
}
that's the actual function
first thought I could use R.pipeP but can't because then the P.try "magic" won't work any more I guess
P being bluebird
Scott Sauyet
@CrossEye
Sep 16 2015 22:22

If f is not supposed to be a parameter, you could do this:

var func = R.converge(R.nthArg(1), f('foo'), R.identity);

But that's fairly bizzare.

Tobias Pflug
@gilligan
Sep 16 2015 22:23
hehehe, yep
Scott Sauyet
@CrossEye
Sep 16 2015 22:24
Wait a second. This is just tap, right?
Tobias Pflug
@gilligan
Sep 16 2015 22:25
hah, true
Scott Sauyet
@CrossEye
Sep 16 2015 22:25
yes.
var func = R.tap(f('foo'));
Tobias Pflug
@gilligan
Sep 16 2015 22:27
thanks a lot
Scott Sauyet
@CrossEye
Sep 16 2015 22:30
np, turned out to be much easier than I thought at first
Denis Stoyanov
@xgrommx
Sep 16 2015 22:40
@gilligan what is it P.try?
Scott Christopher
@scott-christopher
Sep 16 2015 23:21
So I've managed to pull together a rough (read: probably bugs aplenty) implementation of prisms in ramda: https://github.com/ramda/ramda/compare/master...scott-christopher:prisms
Scott Sauyet
@CrossEye
Sep 16 2015 23:22
Great, something new to learn! Oh no, something new to learn!
Scott Christopher
@scott-christopher
Sep 16 2015 23:22
:D
Denis Stoyanov
@xgrommx
Sep 16 2015 23:25
@CrossEye when you plan version 1 of Ramda?
Scott Christopher
@scott-christopher
Sep 16 2015 23:25
It's an attempt at a port from @joneshf's lens library in purescript, while trying to keep the custom types to a minimum
David Chambers
@davidchambers
Sep 16 2015 23:27
@scott-christopher, I'm very excited to see this!
Scott Christopher
@scott-christopher
Sep 16 2015 23:28
The one obvious remaining type is Market (don't ask me for the etymology), which I'm still trying to work out whether it can be simplified.
David Chambers
@davidchambers
Sep 16 2015 23:28
It's a little intimidating. I've no idea what (b2t, s2Eta, pafb) means. ;)
Scott Christopher
@scott-christopher
Sep 16 2015 23:28
Yeah, I should JSify the arg names
b2t is a function from b to t, in terms of s t a b
s2Eta is a function from s to Either t a
To avoid introducing an Either type, I've created a choice function that mimics either :: (a -> c) (b -> c) Either a b) -> c
Where Either a b is represented by a function that can choose to call either it's first or second argument with the result, kinda like the callback for a Promise
David Chambers
@davidchambers
Sep 16 2015 23:32
Ah, that's interesting.
Scott Sauyet
@CrossEye
Sep 16 2015 23:36
@xgrommx: Well, I was hoping to hit version 1 about three months ago. Shows what I know. :smile:
Denis Stoyanov
@xgrommx
Sep 16 2015 23:36
@CrossEye :smile:
David Chambers
@davidchambers
Sep 16 2015 23:38
I don't mind when we hit v1.0.0, so long as we're happy to release v2.0.0 three months later and v3.0.0 three months after that.
Scott Sauyet
@CrossEye
Sep 16 2015 23:41
We need to figure out compose wants to be when it grows up. I also want to figure out the key-sorting question. After that, I'm happy to start thinking again about 1.0. And no, I don't mind if we go to 2.0 soon after, but the goal would be to start settling down.
Richard Burton
@ricburton
Sep 16 2015 23:42
Hey everyone, @davidchambers and I have been bouncing around some ideas to improve the Ramda docs, and we’d love your thoughts on the work so far.

The main thought is that docs need to work for three audiences: beginners, users & contributors. Here are my sketches around this idea: https://www.icloud.com/sharedalbum/#B065nhQST2vh0X;EE34F6CF-C67E-435D-943A-6967E115F26D

This is my first mockup of a docs page with an experience level dropdown: https://cloudup.com/ctfy7nDkUOc

This is my ideal searchbar: results from the docs, stack overflow, Github & Gitter: http://jmp.sh/W07o4tC

This shows the docs are in beginner mode by default with a focus on installation and tutorials. Switching them could drop a cookie so more experienced users only have to do that once: http://d.pr/i/17uiB

Scott Sauyet
@CrossEye
Sep 16 2015 23:46
Absolutely love these ideas. Any idea how to implement them?