make gt, gte, lt, lte, etc... right associative

actual:
var gtFive = R.gt(5);
gtFive(6); // => false

proposal:
var gtFive = R.gt(5);
gtFive(6); // => true

:+1:

been down this road before. Under this proposal gte(5)(6) !== gte(5, 6). that is surprising. this is where the placeholders came from, the desire to right-section the non-commutative infix operators.

I'm not suggesting shenanigans. I'm in favour of swapping the order of the arguments. One can easily write x < y if both values are known, so these functions are primarily useful in conjunction with partial application. Let's optimize for partial application (as we do elsewhere in the library).

I'm in favour of swapping the order of the arguments.

Does this argument order hold for any non-commutative infix operator converted to prefix?
gt(5, 10) === true // ?
divide(20, 2) === 0.1 // ?
subtract(10, 9) === -1 // ?

How about concat?
Feels very familiar.

divide and subtract, absolutely!
concat I'm not sure about. I do like the fact that R.reduce(R.concat, '', ['foo', 'bar', 'baz']) evaluates to 'foobarbaz'.

I do like the fact that R.reduce(R.concat, '', ['foo', 'bar', 'baz']) evaluates to 'foobarbaz'.

That's my take on the whole concept.  Although I'm very frustrated by gt(5) not feeling correct, enough so that I've gone searching for solutions that lead us down inappropriate paths in the past., equivalences like these seem pretty important.  It's not just concat.1
R.reduce(R.subtract, 12, [1, 2, 3, 4])

should be equivalent to
12 - 1 - 2 - 3 - 4

This proposal would replace that with
4 - (3 - ( 2 - (1 - 12)))

which is neither as intuitive nor as understandable.
My biggest difficulty is with the fact that I would want to remain consistent across all our operators.  Here, I think are all the current functions that can reasonably be called operators, including a few more questionable ones (merge, range, zip, zipWith), with the non-commutative ones highlighted.

add
both
concat
difference
differenceWith
divide
either
equals
gt
gte
identical
intersection
intersectionWith
lt
lte
mathMod
max
maxBy
merge ?
min
minBy
modulo
multiply
range ?
subtract
union
unionWith
zip ?
zipWith ?

If we were to change subtract, should we not also change difference?  And yet all prior art I can find for this in other libraries or languages, all have the same API order as Ramda currently supplies for this function.
I really would like to solve the underlying problem.  I simply don't see how to do that.
So I'm afraid I'm :-1: on this.
1I think I first saw this in John Hugh's seminal paper, Why FP Matters, where he points out that

One way to understand (foldr f a) is as a function that replaces all occurrences of Cons in a list by f, and all occurrences of Nil by a. Taking the list [1, 2, 3] as an example, since this means
Cons 1 (Cons 2 (Cons 3 Nil))

then (foldr (+) 0) converts it into
(+) 1 ((+) 2 ((+) 3 0)) = 6

With infix operators, this is nicer still, essentially replacing commas with operators.

How about providing flipped versions, either suffixed (gt_, lte_, etc), or as a properties (gt._, ...)?

How about providing flipped versions

we had that for a while. dropped in favor of placeholder e,g. var greaterThan5 = R.gt(R.__, 5)
I'd be happy to see those come back and placeholder go away.

How about providing flipped versions, either suffixed (gt_, lte_, etc), or as a properties (gt._, ...)?

People have really not liked properties like this in the past, but I like the suffix.  At one point we had divideBy and subtractN, but there was never a good answer to how to extend this to things like gt.  The suffixed version would do this unambiguously.
If we go this route, the big win, as @buzzdecafe points out, would be allowing us to drop the placeholder.  But I think to do that we might want to add a partialN function to compensate for the lost functionality -- just a function to partially apply argument n.  That's a minor detail, though.
I really like this idea!

I'd be happy to see those come back and placeholder go away.

Getting rid of placeholders would certainly be nice.
No matter how the parameters are arranged one use case is going to be awkward. It will either be R.gt(5) or R.zipWith(R.gt, [1,2,3], [3,2,1]).
I think suffixed versions would actually be a nice compromise. Having a suffix _ meaning "slightly different version" could be useful in other cases as well.

Why do you consider placeholders a bad thing?
I'm almost certain I would miss them were they abolished.

@raine They certainly can be very nice. There was some related discussion in #1363.

To throw another suggestion into the mix, perhaps we could offer them as unary functions that return predicates instead, e.g.:
isGt :: Ord a => a -> (a -> Boolean)
isLt :: Ord a => a -> (a -> Boolean)
// etc.
isGt(5) :: Number -> Boolean

@scott-christopher:  We could, but I think that would become more ad hoc.  The advantage of the suffix is that the same solution that works for gt also works for subtract.
And with the underscore as the suffix it retains something of the feel of placeholders while making me think just a bit about right sections.

@CrossEye You're right, that would only make sense for functions returning boolean values. I could get behind the underscore suffix as somewhat of an analog to a prime.

I have been thinking the same way as @scott-christopher. I would prefer a function isGt and subtractBy. These names are IMO much better than gt_*
* The suffix _ is a ramda standard that means that the function is slightly different than the original one. It probably means that the function is flipped but could really be anything and you'll need to figure out exactly what by reading the docs.

It probably means that the function is flipped but could really be anything and you'll need to figure out exactly what by reading the docs.

:laughing:

The advantage of the suffix is that the same solution that works for gt also works for subtract.

Are we really interested in having flipped gt? gt_ would be equal to lt and lt_ would be equal to gt. I.e. they would just be aliases.

Are we really interested in having flipped gt? gt_ would be equal to lt[e] and lt_ would be equal to gt[e]. I.e. they would just be aliases.

that's true. the only thing motivating this discussion is that gt(5) does not mean "greater than five", for that you have to either flip(gt)(5) or gt(__, 5).

Are we really interested in having flipped gt? gt_ would be equal to lt and lt_ would be equal to gt. I.e. they would just be aliases.

In the United States, voting age is 18.  People who haven't reached their 18th birthday are not allowed to vote; those who have, are.  I would much rather express this as
gte_(18)

than as
lte(18)

which does not even come close to expressing my intent.
That's the reason I would like these.

Yes. I do understand how R.gt and R.lt are very unnatural when partially applied.
But Ramda currently has a no alias policy. Thus it seems worth noting that we'd essentially be creating aliases.
Another idea:
R.isGt = R.lt
R.isLt = R.gt

It reads like plain english when partially applied:
R.isGt(17);

I don't have a serious objection to isGt, isLt, etc.  My preference is for the underscore suffix as we could then be entirely consistent, and use it for all non-commutative operator functions.  It is slightly less discoverable than isXX, but is not bad, and it certainly looks cleaner to me than lt(__, 5) or flip(lt)(5).
I'll just be glad to do something to clean this up!

Of the list added by @CrossEye above, if we were to go down the path of additional functions I'd propose only the following be included for now:
* isGt
* isGte
* isLt
* isLte
* divideBy
* subtractBy
* mathModBy
* moduloBy

I was tempted to add concat to the list, however unlike those functions it does feel somewhat appropriate to just apply flip to it.

@scott-christopher:
This list feels reasonably correct.  (I might throw in difference as well.)  But subtractBy doesn't feel particularly appropriate.  There's another issue with *By, going back to Issue #65, where we decided to use With and By prefixes in a standard manner.  somethingBy would accept a unary function that generated a representative value of each element in the list, such as perhaps a sort key.  somethingWith would accept a binary (possibly other polyadic?) function that would accept two elements of the list and use the result of that function in some way.  This has been stretched a bit to cover things like zipWith, where the elements are not actually both from the same list.  And we have an unfortunate holdover from before we created this convention in useWith.  But for the most part, that's how we've been using these suffixes.
My inability to find a good name for a flipped subtract, as well as my own personal inability to come up with isGt, isLte, etc., is one of the reasons that I found subtract_, lt_, etc. attractive.  So, while divideBy sounds just right, and the modulo names are all right with By, it would be a shame to abandon our current convention, especially as subractBy really doesn't capture it at all.  (The previous incarnation was not great, either: subtractN.)

I don't mind the underscore suffix if it means resolving this.
My only slight concern is that it sets a bit of a precedence for the inclusion of functions with very similar functionality to those that already exist by simply adding an underscore to the end, where previously these would have been suggested as additions to the cookbook. I'm not suggesting that we'll actually start approving them, but it may result in more PRs of that nature. Perhaps that's not such a problem ... ¯_(ツ)_/¯

That's one of the reasons my other suggestion was gt**.**_e. Such a solution could be partially automated, so that all binary functions in the library have that property. I can see why people would prefer a simple suffix though.

Btw, objOf is missing in these lists.

Using a postfix _ certainly has it's benefits. It is easy to apply to all relevant names. There is a nice consistency in it. Users would only have to learn about the convention once and would then understand it's meaning in all circumstances we choose to use it in.
One point though: if _ means "flipped" then why not use "F" instead for its mnemonic value?
I don't think it solves the main problem though: that in the current API the most intuitive thing to do yields the wrong result. Adding a _ postfixed flipped version is not going to solve that! People will still have to know that R.gt(5) is misleading and not what they want even though it seems right.
I think R.isGt comes closer to solving that underlying problem because R.isGt(5) reads better than R.gt(5) and thus guides users toward the right choice.
I'm guessing that to someone who has never used Ramda before this:
R.map(R.isGt(3), [1,2,3,4,5]);

will look more sensible than this:
R.map(R.gt_(3), [1,2,3,4,5]);

To me an API design goal is that users can look at the function names only and reasonably guess which function is appropriate.
With the above goal in mind we could rename R.subtract to R.subtractFrom and then make R.subtract a flipped R.subtractFrom. Again, these names would guide users towards the right choice:
R.map(R.subtract(4), [1,2,3,4]); // [-3,-2,-1,0]
R.map(R.subtractFrom(4), [1,2,3,4]); // [3,2,1,0]

Both of the above seems natural to me.

@paldepind:  That sounds quite reasonable.  I think it captures almost everything.  We still need to address the modulo.  modulo(5) sounds the same way subtract(5) or gt(5) does.  If we can find a good version of these, I'd be happy at least addressing them this way.  Because I agree that isGt(5) reads much better, and is much easier to discover.

Lots of good things mentioned here. I think it would make sense if we can distinguish based on infix operators.
The problem is subtract, gt, concat, etc. are typically associated as infix operators. In the Ramda, curried style where data comes last, R.subtract(12) should subtract 12 from the second argument. The following makes a lot of sense to me:
R.pipe(
  R.add(10),
  R.subtract(2),
  R.divide(4)
)(0)
// 2

If becomes confusing when you write it out R.subtract(12, 10) // -2 but thats because you're used to subtract being an infix operator 12 - 10. So I'd vote for suffixing/prefixing to indicate the infix form. So perhaps R.subtract_(12, 10) // 2.
I think a solid test for the proper, non-infix form, is to think of what is more intuitive while piping... Concat is another example of an infix operator that is currently "backwards" in my opinion (although i never thought of it that way until just now):
R.pipe(
  R.last(2),
  R.concat([5, 6, 7]),
)([1, 2, 3, 4])
// [3, 4, 5, 6, 7]

That makes sense, but concat will add it to the beginning currently...

Here's what I'm still thinking, based on previous conversation in this thread.  I know it was back and forth, but in the end, this is what sounded best to me.  The actual names are still flexible, but this is the idea that seems to work best:
   Binary                                          |        Unary

-------------------------------------------------------|----------------------------
gt(8, 5); //=> true;                                 |isGt(5)(8); //=> true 1
gte(8, 5); //=> true                                 |isGte(5)(8); //=> true 1
lt(5, 8); //=> true;                                 |isLt(8)(5); //=> true 1
lte(5, 8); //=> true                                 |isLte(8)(5); //=> true 1
divideInto(12, 4); //=> 3 1               |divide(4)(12); //=> 3 2
subtractFrom(8, 5); //=> 3 1              |subtract(5)(8); //=> 3 2
moduloOf(24, 7); //=> 3 1                 |modulo(7)(24); //=> 3 2
mathModOf(-24, 7); //=> 4 1               |mathMod(7)(-24); //=> 4 2
concatOnto('abc', 'pdq'); //=> 'abcpdq' 1 |concat('pdq')('xyz'); //=> 'xyzpdq' 2
1 New function name
2 Substantial behavior change
As to the comment I made before, we could simply do
R.reduce(R.subtractFrom, 12, [1, 2, 3, 4])

which would be equivalent to
12 - 1 - 2 - 3 - 4

I would even consider making the unary functions purely unary.  For instance:
subtract :: Number -> (Number -> Number)

But that's not essential, and would require significantly more contemplation.
What do others think?  Obviously there would have to be good descriptions, and cross-links between the related functions, but do you agree that this would be about as useful and usable as we could make it?

I'm in favour of sticking with what we have now. gt(_, 0) seems fine to me, and even if we add isGt, gt(0) will still trip people.

I think consistency is most important.
I was introduced to Ramda with the premise that all the arguments are "backwards", but its the proper order for function composition. This is mostly true right now -- map and filter work much better this way. But there are many functions that aren't properly "backwards".
R.pipe(
  R.filter(R.lte(2)),
  R.map(R.subtract(2)),
  R.concat([1,2,3])
)([1,2,3]
// expected: [-1, 0, 1, 2, 3]

I like the suggestions given by @CrossEye but I don't think there's any need for to contain both forms and make up semantic names like isGte vs gte. Its not intuitive to me which is which. The sound like the same function. If we had some kind of convention where we have flipped / infix operators like R._gt by leading with a _, I think that would be most understandable.

I think we have several different issues here.  Although they can be related, discoverability and readability are not the same problem.  This:
R.filter(R.gt(3), [1,2,3,4,5]); //=> [1, 2] // WTF?

fails badly at readability.  Given the number of times this issue has come up in various forums, the current solution,
R.filter(R.gt(R.__, 3), [1, 2, 3, 4,5]); //=> [4, 5]

is failing pretty badly at being discoverable.  I'm pretty sure this is true even for people who do know about the placeholder.  I've fallen prey to it myself.  The trouble is simply that the function reads like what one wants from it.  Generally, in Ramda, when the function reads the way you expect it to act, it works that way too.
One you understand the issue, it's easy enough to employ a placeholder or a flip to get what you want, but the result, with either, but especially with a flip, still suffers from readability problems:
R.filter(R.flip(R.gt)(3), [1, 2, 3, 4,5]); //=> [4, 5]

Even if you import the R variables into your scope to clean it up, it still feels much more obscure than one would want:
filter(gt(__, 3), [1, 2, 3, 4,5]); //=> [4, 5]

I don't see any beautiful answers to our problem.  It's been discussed to death in this thread and others.  So to me, the trick is to make our code both as readable and discoverable as we can.  I believe our current solution is neither.  No matter what we do, we will have some problems with possible misinterpretations, so to some extent, we will always be left expecting documentation to help with discoverability.  But here, a well-named function would be much clearer.  If the documentation for gt mentions odd issues with the curried form, a user is still more likely to understand that "see also isGt" would likely help than she would "see also gt_" or "see also _gt".)  The result is not only more readable, I think it's also more discoverable.
There's one other possibility that just came to me, would be to use operator symbol string the way nucleotides did:
R.filter(R.gt(3), [1, 2, 3, 4,5]); //=> [4, 5]
//but
R.op['>'](3, 5); //=> false

I haven't really thought this through, and again, I might in doing this expect that such named operators as gt were strictly unary.  But it's an interesting concept.

R.op['>'] is an interesting idea.
We needn't use the symbol, though. We could have R.gt and R.op.gt. I could get behind this. I'd really appreciate having access to both R.concat and R.op.concat ("suffix" and "prefix").

We could have R.gt and R.op.gt.

I hadn't considered that.  I've been quite opposed to adding any internal namespacing inside Ramda. (Except, I guess, when I had those functions like map.idx -- "A foolish consistency...")  But I might be able to get behind this.  This would allow us to get left and right sections without any further ado.  And as this would only be for binary operators, the implementation could be a simple flip.
Although, as I keep noting, we might want to consider making the right sections strictly unary::
gt :: Ord a => a -> (a -> Boolean)
op.gt:: Ord a => a -> a -> Boolean
gt(5)(10); //=> true, additional parameters to `gt` ignored
op.gt(5, 10) ≍ op.gt(5)(10); //=> false

Namespace for operators? I wish I had suggested that. Oh wait -- I did https://github.com/ramda/ramda/issues/175#issuecomment-54825655
:stuck_out_tongue:

+1 for namespaced flipped version.
As for the order of the "unflipped" version, I still stand by consistency. You like this version:
filter(gt(__, 3), [1, 2, 3, 4,5]);

filter where something is greater than three.

But then why isnt everything like that?
map(__, R.inc)

But then why isnt everything like that?
map(__, R.inc)

I don't understand this question. In the example, the placeholder is there for the first argument, a function  a -> b. The second argument should be a functor of some kind.

If map took the array first... then you'd do map(__, R.inc). This is effectivly what going on when you do gt(__, 3)

ah i see, you are illustrating the inconsistency that would arise from changing the behavior of curry for infix operators. ok, carry on then, i'm 100% with you

If map took the array first... then you'd do map(__, R.inc). This is effectivly what going on when you do gt(__, 3)

I'm not sure, but I think this is based on a misapprehension of Ramda's chosen ordering.  I believe I've seen you mention somewhere (can't recall where) that Ramda's parameter order is often backwards.  I haven't bothered responding to that, as it hasn't seemed important, but it does miss the point.
Ramda's parameter order is different from Underscore's/lodash's version, which, right or wrong, took the OO style of Array.prototype methods, and moved the data into the first parameter.  Ramda chooses a different order because it makes more sense when currying.  When you curry, the best bet is if the parameters are ordered from the least likely to change to the most likely to change.
It is much more likely to want to build a function that maps a specific function against any number of different lists/functors than one that maps any number of different functions against a fixed list/functor.  It's not that the latter is never possible, only that it much less common.  Hence,
// map:: Functor f => (a -> b) -> f a -> f b
const squareAll = map(square);

instead of
// map2:: Functor f => f a -> (a -> b) -> f b
const opOnSmallPrimes = map2([2, 3, 5, 7, 11]);

This is backward from Underscore, but how it compares to the native prototype is a more difficult question.  It's the same order as in many functional languages, though, so it would be just as correct to say that Underscore is backwards.  But neither perspective is very helpful.
The big trouble comes with these non-commutative binary operators.  There is a clear contradiction between the best order for currying and the obvious order for infix functions.  That's still what this debate is about.

I finished that last one off in a hurry.  By "the best order for currying" I mean something fairly specific: a parameter more likely to change should come after one less likely to change.
For a relative handful of functions, this is not clear: the two parameters are about equally likely to change.  Pretty much all binary operators are like that.  But binary operators have one other feature to dictate their ordering: infix notation.  Since subtraction is written as a - b, with the minuend on the left and the subtrahend on the right, this gives us a clear answer to how these should be ordered as a plain binary function: subtract(a, b).  The opposite feels really wrong: subtract(7, 4); //=> -3 ???
And then we are stumped, not by the math, not by currying, but by English, where grouped together in a partially applied version like subtract(5), it's extremely hard to read as anything other than an operation that subtracts 5 from whatever is passed to it.  That's why this keeps coming up, and why I would really like to find something that works well for us.  I feel that most of the time, once you become accustomed to Ramda's basic ideas, there's very little surprising.  Right now, the behavior here is too surprising.

When I say the order is "backwards", I really mean it in quotes, as in backwards from what we've been accustomed to before Ramda. As you said it facilitates currying. And thats why all my examples have illustrated how some of these functions dont facilitate currying when you're using them with R.pipe or R.compose.
I personally thing those examples are sufficient. Just as people always think at first: map(f, list) was unexpected, they warm up to the idea and understand why. While subtract(7, 4); //=> -3 ??? is unexpected at first, I think its similar, and you'll eventually come to expect it since its consistent with every other function in Ramda. Not to mention, if you wanted an infix operation, you'd just write 7 - 4.
I thiknk we've made our points. Not much left to say. How about we vote on it?

While subtract(7, 4); //=> -3 ??? is unexpected at first, I think its similar, and , you'll eventually come to expect it since its consistent with every other function in Ramda.

That's what I'm not buying.  There is nothing in Ramda that offers guidance here.  Subtraction is an operator.  The two operands are of equal importance, and equally likely to change.  Nothing propels us to choose the anti-infix (?!) order.  On the other hand, I might be warming up to the notion that there is nothing inherently wrong with reversing the order for these.  Nothing is really compelling that notation either, and doing so would clearly solve this problem.

Not to mention, if you wanted an infix operation, you'd just write 7 - 4.

There are plenty of times when you might want to supply an unknown function to operate on your two operands.  In those cases, they have to be pure functions and not simply expressions.

I think we've made our points. Not much left to say. How about we vote on it?

That's not how things work around here.  We generally wait for a consensus to emerge among interested parties, or at least among the core contributors.  If one does not seem likely, we generally don't make any changes, unless we're in an incredibly broken state, and then we might end up using the majority opinion among the core team.  But that's rare.

I just had the same issue, expecting R.filter((x) => x > 2, [1,2,3,4,5]) to be equivalent R.filter(R.gt(2), [1,2,3,4,5]).
But by stopping and thinking why I expected that I realized it's because in Haskell: filter (>2) [1,2,3,4,5], is actually flipping the lt (3 > 2 == (>2) 3), but in such a sofisticated way that fells natural and makes sense in a filter. It's also natural to write map (10/) [1,2,3], and you don't even realize it's actually not making it prefixed, only surrounding with parent. All in all, I guess we have to live w/ the language we have...

I guess we have to live w/ the language we have...

On the other hand, there are many very nice, well-behaved languages that transpile to JavaScript ...
the problem of infix-to-prefix conversion for non-commutative functions has haunted this lib for a long time. we've tried a few things, but have run into problems every time. for now, i think the simplest thing to do is to say that when converting infix to prefix the argument order stays the same, irrespective of how that reads (e.g. gt(2) looks like "greater than 2" but is in fact "2 is greater than"), and irrespective of whether the function is commutative.
In other words, punt. :football:

FWIW, I read subtract(7, 4) as "subtract 7 from 4", but only after getting comfortable with currying and partial application.
With reduce(gt(3), [1,2,3,4,5]), would it be too crazy to swap the order of the reducer as well?
That would allow flipped versions of those functions to behave in the expected way, but I'm not sure what other implications it would have.

+1 to @MattMS. I wonder, too, if flipping reducer's signature has any negative impact. Maybe mapAccum, reduceBy, reduceWhile, transduce should be changed due to consistency.
@CrossEye wrote two operands are equally important, but some people already feel unnatural to this.
If beginner's unfamiliarity is problem, it's also problem that my library is unfamiliar in the present situation. (Though it's not ramda's problem, but it emphasizes importance of consistency.)
I think this kind of consistency is more important than infix notation consistency.
Flipped version of operators, well, that's out of my concern. It can be added if necessary, but are we having any existing flipped version of function? We already have flip and partialRight.

@MattMS

With reduce(gt(3), [1,2,3,4,5]), would it be too crazy to swap the order of the reducer as well?
That would allow flipped versions of those functions to behave in the expected way, but I'm not sure what other implications it would have.

No, it would not be too crazy. In general when using currying that order is more useful. Fortunately we have reduceRight which has that argument order.

@paldepind are you saying (acc, value) or (value, acc) is better for currying?
My thought is the latter, but mine is a fairly inexperienced opinion.
The docs for reduceRight don't seem to explain the reason for using (value, acc), but I guess it is something to do with it traversing right-to-left.

@MattMS
Sorry for the confusing :sweat_smile: I'm saying that what you're suggesting (value, acc) is better for currying. Actually reduceRight was recently changed to that. The discussion leading up the the change is here. Basically that argument order arises "naturally" for reduceRight as I argued in the issue. IMO reduceRight should be used as the "default" reduce function unless one has a specific need for a left fold.

Thanks for the clarification 😄
The examples from #1972 show the flipped reduce* arguments are nice when observing the entire process (value + (value + acc)) but this issue seems to come from observing the specific parts of the process (gt(5)).
My thought is making the latter make sense (by flipping both reduce and gt, subtract, etc) would make things less surprising than focusing on the former.
That said, I'm cautious in my suggestion since my experience has only been in small systems, so flipping reduce arguments (to be (value, acc)) may have issues in larger compositions that I have not encountered.
It's an interesting suggestion about using reduceRight as default too, when considering I often break my Arrays over many lines, which would mean it is reduceBottomToTop. 😛
As an aside:
Reading various issues here has been a great education into the reasoning in functional programming.
It makes me think many issues could be a really useful basis for manual pages, especially with links from the API docs to them.

I'll concede the proposed backward argument order would definitely confuse the heck out of users coming from Lodash.
But the thing is, it would confuse them in the exactly same way as the other functions in Ramda, at which point they'll see the pattern and realize the library has been optimized for partial application.
I'd say confusing Lodash users in a consistent matter would be a good thing. Heck, we'd be doing them a disservice by not confusing them with these functions, as it'll just end up taking longer for them to 'get' Ramda.

Those following this issue may also have opinions on sanctuary-js/sanctuary#239.

@tycho01:
I'm not even slightly worried about confusing users coming from Underscore/lodash.
The concern as always is that the partial application, while extremely important, is not the whole picture.  And there does not seem to be a great solution.
These would be surprising:
R.subtract(12, 5); //=> -7
R.gt(10, 20); //=> false

Although I like the direction Sanctuary is headed on this, I'm not sure it's right for Ramda.  I really don't like decorating function names with punctuation.
But the best solution we've had here is the isGt one, which still leaves the main functions as surprising when partially applied.
Maybe the best alternative is to make these permanently curried, and never allow subtract(a, b), only subtract(a)(b).  But that's also very inconsistent with the rest of Ramda.
Arrggh.

@CrossEye: Hmm. Perhaps it's been a matter of how I've come to view and interpret Ramda. I guess I'd somehow come to associate the left hand of an infix operator as analogous to the 'left hand' (i.e. calling object) in method expressions for the purpose of point-free syntax in partial application, and presumed the parameter order to by necessity be dictated by that. In that interpretation, I suppose there wasn't much contention between the wholly/partially applied versions.
So that's just an N=1 interpretation, and I'd be curious how other Ramda users would interpret these functions in their wholly-applied form without prior knowledge on them.

I guess I'd somehow come to associate the left hand of an infix operator as analogous to the 'left hand' (i.e. calling object) in method expressions for the purpose of point-free syntax in partial application, and presumed the parameter order to by necessity be dictated by that. In that interpretation, I suppose there wasn't much contention between the wholly/partially applied versions.

I'm confused by this.  I feel as though you are suggesting the same thing I would expect and coming to an opposite conclusion.
subtract(7, 3);
// is similar to

7.subtract(3) # in some Ruby-like syntax.

// which to my mind would definitely have to be
//=> 4
// Are you expecting -4 instead?

Right, the Ruby-style 7.subtract(3) matches my method metaphor. Essentially, where I'm coming from is that my interpretations differ between this traditional imperative method-based context versus this FP-optimized context I'm considering Ramda part of.
Interpretations in the traditional (method-based / imperative) context:
1.inc() // 2
['a','b'].append('c') // ['a', 'b', 'c']
'foo'.replace('o', 'e') // 'fee'
7.subtract(3) // 4

Imagined equivalents in the Ramda context, in this interpretation of the imperative method subject coming last (to allow point-free partial application for elegant function composition purposes):
R.inc(1) // 2
R.append('c', ['a','b']) // ['a', 'b', 'c']
R.replace('o', 'e', 'foo') // 'fee'
R.subtract(3, 7) // 4

I imagine the OP here may have come from a similar train of thought.
Admittedly this Ramda context may not be evident to someone who has only been familiar with the former one. I'd like to think there's a certain consistency to it though, and that this should make it easy to get used to this new context.
Does that help clarify?

Well, it definitely means that we do read it differently.
I would find this really surprising:
R.subtract(3, 7); //=> 4

It might still be our best bet.  But that maps very clearly to 3 - 7 in my mind.  And R.modulo(15, 6) maps to 15 % 6.  R.gt(12, 5) is slightly more ambiguous, but does associates more closely with 12 > 5 than with the reverse.  It clearly does not feel right.
Perhaps it's time to resurrect https://github.com/ramda/ramda/issues/1497#issuecomment-195644724.

It sounds like a reasonable compromise, yeah.
Restricting them to unary usage I would consider as surprising compared to the other functions without such limitation. It might also be harder to explicitly express in the Hindley-Milner type notation used in the docs...

I would find this really surprising:
R.subtract(3, 7); //=> 4

But R.map(f, xs)  is equivalent to xs.map(f), so would it be inconsistent for R.subtract(3, 7) to equal 7.subtract(3) ?

It might also be harder to explicitly express in the Hindley-Milner type notation used in the docs...

We could use parens:
gt :: Ord a => a -> (a -> Boolean)

But R.map(f, xs)  is equivalent to xs.map(f), so would it be inconsistent for R.subtract(3, 7) to equal 7.subtract(3) ??

Even if that were true, I think we need to consider readability and discoverability alongside questions of internal consistency.
But I don't think it's true.  Technically, of course it's not:
const f = R.inc;
const g = multiply(2);
R.map(f, g)(5); //=> 11
g.map(f)(5); //~~> Error: g.map is not a function

or
const square = (x) => x * x;
const xs = {a: 1, b: 2, c: 3};
R.map(square, xs); //=> {"a": 1, "b": 4, "c": 9}
xs.map(square); //~~> Error: xs.map is not a function

Or even for lists:
const xs = ['1', '2', '3'];
const f = parseInt;
R.map(f, xs); //=> [1, 2, 3]
xs.map(f); //=> [1, NaN, NaN]

But I mean more than this technicality.  To me, parameters are ordered in a straightforward manner: a parameter less likely to change comes before one more likely to change.  Usually, this simply dictates the parameter order.  But in some odd cases, several parameters seem equally likely to change.  Binary operators fall into this category.  With subtraction, for instance, there is no reason to expect the minuend to change more often than the subtrahend.
These are not the only cases.  But others like propEq can make arbitrary decisions that have to be documented but that don't have to match common expectations.  There is a normal expectation, I believe, that for a function which is serving in the place of an infix operator, the parameters would appear in that order.  The trouble is that the English language used to describe them sounds like the reverse when partially applied.  We would have no issue at all with
// foo:: Number -> Number -> Number
const foo = curry((a, b) => b - a)

No one would think twice that foo(3, 7); //=> 4 or that foo(3); //~> (b) => b - 3.  If you substitute 'subtract' for 'foo', one of those statements is likely surprising.
The rationale, of course, for the parameters less likely to change to come before those more likely to has to do with making these functions easier to compose through currying.  But that is done in the absence of any competing pressure.  Generally we can simply make a decision about how to order the parameters to our functions as we choose.  (I don't consider the prior art of jQuery, Underscore, lodash, etc. to be competing pressure at all; nor do I think that something like Array.prototype.map has any influence.  Those are too far from the style of work Ramda is trying to support.)  But for these binary operators, the English language and the common idioms of arithmetic  do provide a push in the opposite direction.  Here is where I really get language envy.   The ability to include left and right sections, the ability to convert between prefix and infix, and other such features makes me want to be working in Haskell.

But, the more we live with the current versions, the more that we need to have these same discussions, the more I think that we might simply be best off ignoring the issue of readability of the fully applied versions and think about how we would like to present these with a flipped order.
As @davidchambers notes, we can simply do
gt :: Ord a => a -> (a -> Number)

and
subtract :: Number -> (Number -> Number)

I know I personally would have fewer issues with this than with the current versions.  Although I do sometimes use the fully applied version, I'm much more likely to curry in the one I want, and remembering to add the placeholder, or even reading the code with the placeholder, is harder than it would be if we flipped.
So, @asaf-romano, @buzzdecafe, @davidchambers, @kedashoe, @paldepind, @raine, @scott-christopher, @TheLudd, what so you?  Is it time we switch?  If so, which functions?  All of the list in https://github.com/ramda/ramda/issues/1497#issuecomment-153929590?  Or some smaller set?

FWIW, my personal usage makes me think the subtrahend is less likely to change than the minuend.
Same with the right argument in comparison, in value < limit, wouldn't the limit be more likely to be fixed?
Apologies for commenting if your call-outs were indicating this discussion should now be limited to core contributors.

Apologies for commenting if your call-outs were indicating this discussion should now be limited to members only.

Not in the least; there is a separate channel for that.
I agree entirely.  But the tension is between the partially applied and the fully applied versions.

My preference would still be to introduce the following unary functions while deprecating their existing counterparts.

isGt
isGte
isLt
isLte
divideBy
subtractBy (perhaps subtracting?)
mathModBy
moduloBy

I have a proposal for Sanctuary in https://github.com/sanctuary-js/sanctuary/pull/391#issuecomment-300962716 inspired by Haskell's infix operator sections.
It may also be appropriate for Ramda.

@gabejohnson

It may also be appropriate for Ramda.

As I said there, this is the best proposal I've yet seen in this never-ending debate. I will try to make a PR using this, unless you want to do it.

@CrossEye it's all yours. I'd suggest getting all of the operators you listed in https://github.com/ramda/ramda/issues/1497#issuecomment-153929590 on that same page as well.

Sanctuary now provides this behaviour:
const S = require('sanctuary')

S.gte
// => gte :: Ord a => a -> (a -> Boolean)

S.gte_
// => gte_ :: Ord a => a -> a -> Boolean

S.filter(S.gte(0), [0, -1, 2, -3, 4])
// => [0, 2, 4]

S.gte_(0, 42)
// => false

S.gte(0, 42)
// ! TypeError: Function applied to too many arguments
//
//   gte :: Ord a => a -> (a -> Boolean)
//
//   ‘gte’ expected at most one argument but received two arguments.

as fro me, it should work like this:
R.gt(10, 5); // => true
R.gt(10)(5); // => true

(which is also how it works now)
because as I am thinking about it, the operator is > and it's applied between the 2 arguments (10 > 5). (reason I am thinking about it like that is probably clojure https://clojuredocs.org/clojure.core/> where it works exactly this way)

I don't know Clojure, so please excuse me guessing at the syntax.
Does that mean (filter (> 2) [1 2 3 4]) equals [1 2]?
If so then I guess they don't see the partial application as an issue.
But to me it still seems confusing.

@MattMS no. the result is [1] (2 is not less than 1).
Partial application means that you provide not all arguments to the function, which creates function taking rest of the arguments. Right? So the way it currently works:
// 10 > 2
R.gt(10, 2) // => true

const is10GreaterThan = R.gt(10);
is10GreaterThan(2); // => true

so as for me - it works as it should.
note that in Haskell, which is language where all functions are currying, it works exactly the same way.
(>) 10 2 -- => True

let is10GraterThan = (>) 10
is10GreaterThan 2 -- => True

you can think of writing (>) 10 2 in Haskell as writing R.gt(10)(2) in ramda.
see http://learnyouahaskell.com/higher-order-functions for mor information on how currying works in Haskell.

To further improve consistency with these function names, I propose we rename isEmpty to isFull. 😃

@nenadalm Regardless of other languages (imho people can always transpile to JS) I think naming R.gt(10) as is10GreaterThan goes against how RamdaJS works.
I always think of R.<some action>(action parameter) in the way of "Apply the action specified with the parameter on the subject". E.g. R.contains, R.prepend, R.omit... (the "subject" being a JS collection) all work this way.
R.gt(X) reads like "greater than X" with the subject being on the left side of the comparison. Because this is not the case in Ramda today so many people have problems with R.gt(X).

@semmel see #2177 for an alternative.

I really think we should swap the argument order of gt, lt, subtract and more where it makes sense before 1.0.0. This issue just came up again on the gitter channel. To this day this is still something that confuses users.

... but as always, at the expense of those who reasonably expect subtract(10, 7) //=> 3
I really, really want left/right sections.

Strict currying is the answer. ;)

The thing is, no one writes that when they can write 10 - 7 instead.

Or 3 :stuck_out_tongue: .
I see this a lot, but there are valid cases where flipping the order would be damn surprising.
Nobody calls subtract(10, 7) but I would wager that stuff like zipWith(subtract, [10, 9, 8], [3, 2, 1]) gets called on occasion, or reduce(concat) to use an example from another discussion here.
With a binary function, we need to consider that it can be fully applied, partially applied, or passed as a parameter to a higher order function with no arguments applied.
The current argument order favors two out of the three cases, but is really surprising for the third case. Flipping the order would simply change which applications were surprising.

The thing is, no one writes that when they can write 10 - 7 instead.

This may be the case for -, but for other operators Ramda could provide more general functions. S.lte (y) (x), for example, is not equivalent to x <= y because S.lte supports any Ord type.

@gabejohnson: I'd forgotten all about that.  I really like that idea.  Will respond over there, though.

Came here for this. Adding my grain of salt by voicing in favor of swapping order. I've found myself, more often than not, writing gt, lt, etc. on compose chains or as stand alone functions and they always look and read weird.
This is a real life example I encountered today:
const doIfConfirmedGreaterThanZero = fn => when(
 compose(lte(0), prop('confirmed'))  // <- semantics contradict function name
);

Alternatives look less hacky, IMHO: gt(R.__, 0), flip(gt)(0), partialRight(gt, [0]).

@Bradcomp

Nobody calls subtract(10, 7) but I would wager that stuff like zipWith(subtract, [10, 9, 8], [3, 2, 1]) gets called on occasion, or reduce(concat) to use an example from another discussion here.

That is a very good point.

The current argument order favors two out of the three cases, but is really surprising for the third case. Flipping the order would simply change which applications were surprising.

Good point as well. But, I'd still say that flipping the order would make the most common application the least surprising one.

@CrossEye

That's my take on the whole concept. reduce(concat, '', ['a', 'b', 'c']) // => 'abc'

How about using flip when passing them to higher order functions.
reduce(flip(concat), '', ['a', 'b', 'c']) // => 'abc'
Notice that the majority of people opt for flipping the arguments. I also do think that we should facilitate function composition and use flip when passing them to higher order functions.

@1024gs:
I don't think that's at all possible.  We don't know when that's happening.  A function doesn't know how and where it's being called.  And a function that accepts another function as a parameter does not know that it is a non-commutative operator.  I see no way to automate this.

@CrossEye

I see no way to automate this.

I don't think they meant that. I believe they were simply suggesting flipping the argument order as a solution, and asking people to use flip() in cases like reduce(concat).

To throw in my $0.02, Ramda already has so many functions and, postfix or otherwise, I think additional functions would just make things worse overall.

@CrossEye
I did not mean to automate it (sometimes automation is the biggest source of bugs).
I meant to make gt, gte, lt, lte, etc... right associative and in cases like reduce(concat) I would suggest, and I think it is a good suggestion, the user to use flip().
e.g. reduce(flip(concat), '', ['a', 'b', 'c']) would evaluate to 'abc'

Here's your suggestion in action, @1024gs:
> S.map (S.sub (1)) ([1, 2, 3, 4, 5])
[0, 1, 2, 3, 4]

> S.reduce (S.flip (S.sub)) (1000) ([1, 2, 3, 4, 5])
985

I've had no problems with this behaviour. :)

I saw a comment indicating that this proposal:
would replace
R.reduce(R.subtract, 12, [1, 2, 3, 4])

With
4 - (3 - ( 2 - (1 - 12)))
I see the logic, though I think I have a problem with the order of parameters in the reducer function as well . The reducer function (I mean the first parameter of the R.reduce) currently receives the accumulation and then the current value... I see the reducer as acting on the data that is being accumulated. Following data last approach, changing the order in the reducer would make this to works again.
const mySubtract = R.curryN(2, (a, b) => b-a)
const myReduce = R.curryN(3, reduce)

myReduce(mySubtract, 12, [1, 2, 3, 4])    // (12 - 1) -2) -3) -4 = 2

function reduce(reducer, ini, array)
{
  let acum = ini
  for (i of array) {
    acum = reducer(i, acum)
  }
  return acum
}

The signature for the reduce:
((a, b) → b) → b → [a] → b
const myReduce = (reducer, ini, array) => {

  let acum = ini
  for (i of array) {
    acum = reducer(i, acum)
  }
  return acum
}

To me append works (data last parameter):
R.append(2, [1]) // [1,2]
Then to be conssistent:
R.concat('s', 'cat') // should return cats... but returns scat.
Changing the order of the params in the reducer and in the concat we see that, it keeps being intuitive.
myConcat = R.curryN(2, (a,b) => b + a)

myReduce(myConcat, '', ['foo', 'bar', 'baz']) //? foobarbaz

I saw a comment indicating that this proposal:
would replace
R.reduce(R.subtract, 12, [1, 2, 3, 4])

With
4 - (3 - ( 2 - (1 - 12)))
I see the logic, though I think I have a problem with the order of parameters in the reducer function as well . The reducer function (I mean the first parameter of the R.reduce) currently receives the accumulation and then the current value... I see the reducer as acting on the data that is being accumulated. Following data last approach, changing the order in the reducer would make this to works again.
const mySubtract = R.curryN(2, (a, b) => b-a)
const myReduce = R.curryN(3, reduce)

myReduce(mySubtract, 12, [1, 2, 3, 4])    // (12 - 1) -2) -3) -4 = 2

function reduce(reducer, ini, array)
{
  let acum = ini
  for (i of array) {
    acum = reducer(i, acum)
  }
  return acum
}

The signature for the reduce:
((a, b) → b) → b → [a] → b
const myReduce = (reducer, ini, array) => {

  let acum = ini
  for (i of array) {
    acum = reducer(i, acum)
  }
  return acum
}

To me append works (data last parameter):
R.append(2, [1]) // [1,2]
Then to be conssistent:
R.concat('s', 'cat') // should return cats... but returns scat.
Changing the order of the params in the reducer and in the concat we see that, it keeps being intuitive.
myConcat = R.curryN(2, (a,b) => b + a)

myReduce(myConcat, '', ['foo', 'bar', 'baz']) //? foobarbaz

@josuamanuel:
I think changing the order of arguments in the reduction function passed to reduce now is a non-starter.  They've been in this order since the first version of Ramda.  They match the order used in Array.prototype.  They match the FantasyLand specification.  They match Haskell's foldl.  They match nearly every library that supports a fold.
Ramda seems stuck with a problem with curried  versus  fully applied non-commutative binary operations.  I wish we had Haskell's sections available.

@josuamanuel:
I think changing the order of arguments in the reduction function passed to reduce now is a non-starter.  They've been in this order since the first version of Ramda.  They match the order used in Array.prototype.  They match the FantasyLand specification.  They match Haskell's foldl.  They match nearly every library that supports a fold.
Ramda seems stuck with a problem with curried  versus  fully applied non-commutative binary operations.  I wish we had Haskell's sections available.

I see your point to reject the change... and I kind of agree. Anyway, and just for the purpose of entertaining our minds, let me explain my view. This is coming from being new into functional programming, and this could be bad for obvious reasons and good to see things in a different way. My approach comes from a language (grammar syntax and semantic) rather than mathematical notation.
We cannot create operators in javascript and we need to express them with functions. The change to functions requires an effort to make them more natural language readable. The fact we use mathematical terminology like non-commutative binary operation to describe functions sounds suspicious to me. We need to embrace the descriptive nature of functions as grammar, syntax and semantic.
This why I was really impressed with the concept of data las parameter of a function. I took some time to adapt coming from lodash, but I like the consistency as a grammar rule. After some little time, I adapted quite well. For the first time I felt I could take a consistency decision about the order of parameters in new functions.
The way I read Ramda code:
R.append(2,[3])
The system or function wants to add a value two acting upon the data [3]
R.append(2)
This is an appender of 2... A worker prepared to add a 2 in any data array.
// This is the flip vevrsion of Ramda.
gt(5,6)
The system/function checks if it is great than 5 giving 6 as data
When considered gt(5,6) and gt(5)(6) both as true from data las parameter perspective it makes sense. Grammar doesn't need to be intuitive at first glance. But consistency and narrative of the language is more important.
I think what it helps me to separate the parameters from the data is to see the semantic of name of the function... the verb + adding -er: What is a divider, what is an adder, a subtracter, a merger, a reducer. As being separated from the data they act upon.
Grammar:
Subject: Omitted in the language as it is understood by the context. The function or the system that wants to do the action.
Verb: function name:
Direct Object. Parameters
Indirect Object or Complements: data (last parameter)
Probably, making this more language oriented would have changed some verb names to fit better into this semantic.
My intention with the post... is to give another view. I have say I admire the good work that all contributor makes.

I see your point to reject the change... and I kind of agree. Anyway, and just for the purpose of entertaining our minds, let me explain my view. This is coming from being new into functional programming, and this could be bad for obvious reasons and good to see things in a different way. My approach comes from a language (grammar syntax and semantic) rather than mathematical notation.
We cannot create operators in javascript and we need to express them with functions. The change to functions requires an effort to make them more natural language readable. The fact we use mathematical terminology like non-commutative binary operation to describe functions sounds suspicious to me. We need to embrace the descriptive nature of functions as grammar, syntax and semantic.
This why I was really impressed with the concept of data las parameter of a function. I took some time to adapt coming from lodash, but I like the consistency as a grammar rule. After some little time, I adapted quite well. For the first time I felt I could take a consistency decision about the order of parameters in new functions.
The way I read Ramda code:
R.append(2,[3])
The system or function wants to add a value two acting upon the data [3]
R.append(2)
This is an appender of 2... A worker prepared to add a 2 in any data array.
// This is the flip vevrsion of Ramda.
gt(5,6)
The system/function checks if it is great than 5 giving 6 as data
When considered gt(5,6) and gt(5)(6) both as true from data las parameter perspective it makes sense. Grammar doesn't need to be intuitive at first glance. But consistency and narrative of the language is more important.
I think what it helps me to separate the parameters from the data is to see the semantic of name of the function... the verb + adding -er: What is a divider, what is an adder, a subtracter, a merger, a reducer. As being separated from the data they act upon.
Grammar:
Subject: Omitted in the language as it is understood by the context. The function or the system that wants to do the action.
Verb: function name:
Direct Object. Parameters
Indirect Object or Complements: data (last parameter)
Probably, making this more language oriented would have changed some verb names to fit better into this semantic.
My intention with the post... is to give another view. I have say I admire the good work that all contributor makes.

@josuamanuel
The syntax of Ramda is influenced by Lambda Calculus which is often time read from right to left; when you think of everything being a function, it makes a lot of sense.
When you use Ramda within a tacit code-base you also realize that it couldn't be any other way. Tacit programming (or point-free) is a style of programming where no argument are declared (or no points). And so when you think of: if x is greater than 10, well, you know the value 10 but not x; so passing x first doesn't make sense.
Take the following example: if x is less than or equal to 10, then add 1 else return 0;
const fuga = when(lte(10), add(1), always(0));

In summary, Ramda's API always pass the undetermined value last.
If you want gte or lte to read in the other direction, you can always do this: const my_gte = flip(gte);

@josuamanuel
The syntax of Ramda is influenced by Lambda Calculus which is often time read from right to left; when you think of everything being a function, it makes a lot of sense.
When you use Ramda within a tacit code-base you also realize that it couldn't be any other way. Tacit programming (or point-free) is a style of programming where no argument are declared (or no points). And so when you think of: if x is greater than 10, well, you know the value 10 but not x; so passing x first doesn't make sense.
Take the following example: if x is less than or equal to 10, then add 1 else return 0;
const fuga = when(lte(10), add(1), always(0));

In summary, Ramda's API always pass the undetermined value last.
If you want gte or lte to read in the other direction, you can always do this: const my_gte = flip(gte);

fuga = when(lte(10), add(1), always(0));

The example you mention doesn't work to me.  The above syntax currently means:
if 10 is less or equal than x, then add 1 else return 0
rather than the more intuitive (and what you thought it meant):
if x is less than or equal to 10, then add 1 else return 0

fuga = when(lte(10), add(1), always(0));

The example you mention doesn't work to me.  The above syntax currently means:
if 10 is less or equal than x, then add 1 else return 0
rather than the more intuitive (and what you thought it meant):
if x is less than or equal to 10, then add 1 else return 0

The example you mention doesn't work to me. I think you meant:
let fuga = R.ifElse(R.lte(10), R.add(1), R.always(0));

Yes, you're right about that, I meant to use the ifElse combinator -- I probably shouldn't write tech comments 10 minutes after waking up. 🙃
But your argument doesn't take into account the origin of the various combinators implemented by Ramda.
As it was mentioned before, concat is implement based on the Semigroup algebra defined by Fantasy-Land where the first value will be concatenated with a second value and return the first; it's not obvious when you think of concat in term of strings or arrays, but if you allow me to use an example from one of my libraries, it might help make sense.
const file = concat(File("./hoge", new Uint8Array([ 65, 66, 67, 68, 69 ]), 3), File("./piyo", new Uint8Array([ 70, 71, 72, 73, 74 ]), 3));

assert(file.path === "./hoge");
assert(file.raw === new Uint8Array([ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74 ]));

My argument was that the last argument is the undetermined one, so concat and append are consistent.

The example you mention doesn't work to me. I think you meant:
let fuga = R.ifElse(R.lte(10), R.add(1), R.always(0));

Yes, you're right about that, I meant to use the ifElse combinator -- I probably shouldn't write tech comments 10 minutes after waking up. 🙃
But your argument doesn't take into account the origin of the various combinators implemented by Ramda.
As it was mentioned before, concat is implement based on the Semigroup algebra defined by Fantasy-Land where the first value will be concatenated with a second value and return the first; it's not obvious when you think of concat in term of strings or arrays, but if you allow me to use an example from one of my libraries, it might help make sense.
const file = concat(File("./hoge", new Uint8Array([ 65, 66, 67, 68, 69 ]), 3), File("./piyo", new Uint8Array([ 70, 71, 72, 73, 74 ]), 3));

assert(file.path === "./hoge");
assert(file.raw === new Uint8Array([ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74 ]));

My argument was that the last argument is the undetermined one, so concat and append are consistent.

I agree with you that I am not taking the origins of Lambda Calculus and algebra defined by Fantasy-land. I favoured Data last parameter approach overall to favour pipes, partial applications and recipe code style. I see we are dropping data last parameter rule in favour of consistency with the origins for some functions.
Thanks... for all explanations, I understand now the reasons so I can reconcile and accept things as they are.

I agree with you that I am not taking the origins of Lambda Calculus and algebra defined by Fantasy-land. I favoured Data last parameter approach overall to favour pipes, partial applications and recipe code style. I see we are dropping data last parameter rule in favour of consistency with the origins for some functions.
Thanks... for all explanations, I understand now the reasons so I can reconcile and accept things as they are.

@josuamanuel:

The fact we use mathematical terminology like non-commutative binary operation to describe functions sounds suspicious to me.

Understood.  We often let terminology get out of hand.  But it is convenient too.  I hope "binary operation" (or "binary function") is clear: an operation / function that takes two arguments.  While we could use the phrase "binary functions which might yield different results when the arguments are switched", it gets to be a mouthful.  "commutative" is taken from mathematics, and there are plenty of times when I think such terminology goes overboard, I also think there are times when it's quite useful.  Those who've been in the industry a while also had to learn to use such terms as "polymorphic", until by now it just seems natural.

We need to embrace the descriptive nature of functions as grammar, syntax and semantic.

Our real trouble here is that there are conflicting expectations.  We want subtract (7, 3) to yield 4.  It feels most natural.  But we also want subtract (3) to be a function that subtracts three from the argument supplied, so that subtract (3) (7) yields 4.  The way Ramda is built, we can't have it both ways.  If I were to start over, I would insist in focusing on the unary application, and make the binary version follow that, so that subtract (3, 7) would read the way you're suggesting, something like "subtract 3 from 7".  The trouble is that there seem to be no good answers.  And ones like concat or the reduce callback are further constrained by prior art in a way that Ramda would not want to disturb.
I'm afraid I simply don't see good answers here.

@josuamanuel:

The fact we use mathematical terminology like non-commutative binary operation to describe functions sounds suspicious to me.

Understood.  We often let terminology get out of hand.  But it is convenient too.  I hope "binary operation" (or "binary function") is clear: an operation / function that takes two arguments.  While we could use the phrase "binary functions which might yield different results when the arguments are switched", it gets to be a mouthful.  "commutative" is taken from mathematics, and there are plenty of times when I think such terminology goes overboard, I also think there are times when it's quite useful.  Those who've been in the industry a while also had to learn to use such terms as "polymorphic", until by now it just seems natural.

We need to embrace the descriptive nature of functions as grammar, syntax and semantic.

Our real trouble here is that there are conflicting expectations.  We want subtract (7, 3) to yield 4.  It feels most natural.  But we also want subtract (3) to be a function that subtracts three from the argument supplied, so that subtract (3) (7) yields 4.  The way Ramda is built, we can't have it both ways.  If I were to start over, I would insist in focusing on the unary application, and make the binary version follow that, so that subtract (3, 7) would read the way you're suggesting, something like "subtract 3 from 7".  The trouble is that there seem to be no good answers.  And ones like concat or the reduce callback are further constrained by prior art in a way that Ramda would not want to disturb.
I'm afraid I simply don't see good answers here.

Why not drop support for subtract (7, 3) and require subtract (3) (7)? We made this change to Sanctuary several years ago, throughout the library. Not only did this dramatically simplify parts of the implementation, but it made the library easier to understand and use. With Ramda, one must remember that although R.reduce is curried, the function one provides as its first argument must not be. As a Ramda user, this distinction seems arbitrary.
The currying section of Sanctuary's website compares the two approaches.

Why not drop support for subtract (7, 3) and require subtract (3) (7)? We made this change to Sanctuary several years ago, throughout the library. Not only did this dramatically simplify parts of the implementation, but it made the library easier to understand and use. With Ramda, one must remember that although R.reduce is curried, the function one provides as its first argument must not be. As a Ramda user, this distinction seems arbitrary.
The currying section of Sanctuary's website compares the two approaches.

@davidchambers

Why not drop support for subtract (7, 3) and require subtract (3) (7)? … Not only did this dramatically simplify parts of the implementation, but it made the library easier to understand and use.

I guess replacing each , with )( that would make ramda functions look a bit alien in the code base. Also it would make it even harder for the eye to associate the parentheses to the according group.
Here the ifElse example from the docu
var incCount = ifElse(
  R.has('count'),
  R.over(R.lensProp('count'), R.inc),
  R.assoc('count', 1)
);
var incCount = ifElse
  (R.has('count'))
  (R.over(R.lensProp('count'))(R.inc))
  (R.assoc('count')(1))

Without syntax highlighting this would be a nightmare to edit.
When this would be required also for pipe, compose and o it would become even worse looking.
Also when writing lib functions I grew quite fond of ramda-style currying because it gives much freedom for the user: He/she can use the functions in classical style of point-free functional style - it is flexible with regard to the user's philosophy. It has certainly helped me first to become acquainted with ramda and now more and more embracing point-free function pipelines.

R.reduce is curried, the function one provides as its first argument must not be. As a Ramda user, this distinction seems arbitrary.

There are more Ramda functions where this is the case e.g. converge and useWith. (Of course ramda-style curried functions always work).
Here is how some of ramda looks for binary/ramda-curried/strictly-curried functions.

strictly add = a => b => a + b
ramda-style R.add
binary add = (a, b) => a + b
example

chain
✓
✓
-
R.chain(add, R.inc)(7) // 15

ap
✓
✓
-
R.ap(add, R.inc)(7) // 15

useWith
-
✓
✓
R.useWith(R.add, [R.inc,R.multiply(8)])(3,4) // 36

converge
-
✓
✓
R.converge(add, [R.inc,R.multiply(8)])(3) // 28

lift
✓
✓
✓
R.lift(add)(R.inc,R.multiply(8))(3) // 28

reduce
-
✓
✓
R.reduce(R.add, 0, [7, 8]) // 15

Perhaps the gaps in the first column could be filled in the implementations?

@davidchambers

Why not drop support for subtract (7, 3) and require subtract (3) (7)? … Not only did this dramatically simplify parts of the implementation, but it made the library easier to understand and use.

I guess replacing each , with )( that would make ramda functions look a bit alien in the code base. Also it would make it even harder for the eye to associate the parentheses to the according group.
Here the ifElse example from the docu
var incCount = ifElse(
  R.has('count'),
  R.over(R.lensProp('count'), R.inc),
  R.assoc('count', 1)
);
var incCount = ifElse
  (R.has('count'))
  (R.over(R.lensProp('count'))(R.inc))
  (R.assoc('count')(1))

Without syntax highlighting this would be a nightmare to edit.
When this would be required also for pipe, compose and o it would become even worse looking.
Also when writing lib functions I grew quite fond of ramda-style currying because it gives much freedom for the user: He/she can use the functions in classical style of point-free functional style - it is flexible with regard to the user's philosophy. It has certainly helped me first to become acquainted with ramda and now more and more embracing point-free function pipelines.

R.reduce is curried, the function one provides as its first argument must not be. As a Ramda user, this distinction seems arbitrary.

There are more Ramda functions where this is the case e.g. converge and useWith. (Of course ramda-style curried functions always work).
Here is how some of ramda looks for binary/ramda-curried/strictly-curried functions.

strictly add = a => b => a + b
ramda-style R.add
binary add = (a, b) => a + b
example

chain
✓
✓
-
R.chain(add, R.inc)(7) // 15

ap
✓
✓
-
R.ap(add, R.inc)(7) // 15

useWith
-
✓
✓
R.useWith(R.add, [R.inc,R.multiply(8)])(3,4) // 36

converge
-
✓
✓
R.converge(add, [R.inc,R.multiply(8)])(3) // 28

lift
✓
✓
✓
R.lift(add)(R.inc,R.multiply(8))(3) // 28

reduce
-
✓
✓
R.reduce(R.add, 0, [7, 8]) // 15

Perhaps the gaps in the first column could be filled in the implementations?

@davidchambers

Why not drop support for subtract (7, 3) and require subtract (3) (7)? … Not only did this dramatically simplify parts of the implementation, but it made the library easier to understand and use.

I guess replacing each , with )( that would make ramda functions look a bit alien in the code base. Also it would make it even harder for the eye to associate the parentheses to the according group.
Here the ifElse example from the docu
var incCount = ifElse(
  R.has('count'),
  R.over(R.lensProp('count'), R.inc),
  R.assoc('count', 1)
);
var incCount = ifElse
  (R.has('count'))
  (R.over(R.lensProp('count'))(R.inc))
  (R.assoc('count')(1))

Without syntax highlighting this would be a nightmare to edit.
When this would be required also for pipe, compose and o it would become even worse looking.
Also when writing lib functions I grew quite fond of ramda-style currying because it gives much freedom for the user: He/she can use the functions in classical style of point-free functional style - it is flexible with regard to the user's philosophy. It has certainly helped me first to become acquainted with ramda and now more and more embracing point-free function pipelines.

R.reduce is curried, the function one provides as its first argument must not be. As a Ramda user, this distinction seems arbitrary.

There are more Ramda functions where this is the case e.g. converge and useWith. (Of course ramda-style curried functions always work).
Here is how some of ramda looks for binary/ramda-curried/strictly-curried functions.

strictly add = a => b => a + b
ramda-style R.add
binary add = (a, b) => a + b
example

chain
✓
✓
-
R.chain(add, R.inc)(7) // 15

ap
✓
✓
-
R.ap(add, R.inc)(7) // 15

useWith
-
✓
✓
R.useWith(R.add, [R.inc,R.multiply(8)])(3,4) // 36

converge
-
✓
✓
R.converge(add, [R.inc,R.multiply(8)])(3) // 28

lift
✓
✓
✓
R.lift(add)(R.inc,R.multiply(8))(3) // 28

reduce
-
✓
✓
R.reduce(R.add, 0, [7, 8]) // 15

Perhaps the gaps in the first column could be filled in the implementations?

@davidchambers

Why not drop support for subtract (7, 3) and require subtract (3) (7)? … Not only did this dramatically simplify parts of the implementation, but it made the library easier to understand and use.

I guess replacing each , with )( that would make ramda functions look a bit alien in the code base. Also it would make it even harder for the eye to associate the parentheses to the according group.
Here the ifElse example from the docu
var incCount = ifElse(
  R.has('count'),
  R.over(R.lensProp('count'), R.inc),
  R.assoc('count', 1)
);
var incCount = ifElse
  (R.has('count'))
  (R.over(R.lensProp('count'))(R.inc))
  (R.assoc('count')(1))

Without syntax highlighting this would be a nightmare to edit.
When this would be required also for pipe, compose and o it would become even worse looking.
Also when writing lib functions I grew quite fond of ramda-style currying because it gives much freedom for the user: He/she can use the functions in classical style of point-free functional style - it is flexible with regard to the user's philosophy. It has certainly helped me first to become acquainted with ramda and now more and more embracing point-free function pipelines.

R.reduce is curried, the function one provides as its first argument must not be. As a Ramda user, this distinction seems arbitrary.

There are more Ramda functions where this is the case e.g. converge and useWith. (Of course ramda-style curried functions always work).
Here is how some of ramda looks for binary/ramda-curried/strictly-curried functions.

strictly add = a => b => a + b
ramda-style R.add
binary add = (a, b) => a + b
example

chain
✓
✓
-
R.chain(add, R.inc)(7) // 15

ap
✓
✓
-
R.ap(add, R.inc)(7) // 15

useWith
-
✓
✓
R.useWith(R.add, [R.inc,R.multiply(8)])(3,4) // 36

converge
-
✓
✓
R.converge(add, [R.inc,R.multiply(8)])(3) // 28

lift
✓
✓
✓
R.lift(add)(R.inc,R.multiply(8))(3) // 28

reduce
-
✓
✓
R.reduce(R.add, 0, [7, 8]) // 15

Perhaps the gaps in the first column could be filled in the implementations?

@semmel, we addressed the formatting issue in sanctuary-js/sanctuary#438. To me (three years later), this is readable:
var incCount = ifElse (R.has ('count'))
                      (R.over (R.lensProp ('count'))
                              (R.inc))
                      (R.assoc ('count')
                               (1));

One more example:
//    highlightChunk :: String -> Html
const highlightChunk =
def ('highlightChunk')
    ({})
    ([$.String, Html.Type])
    (syntax ('keyword')
            (/\b(const|else|function|if|instanceof|new|return|this)\b/)
            (syntax ('boolean-literal')
                    (/\b(false|true)\b/)
                    (syntax ('number-literal')
                            (/\b([0-9]+(?:[.][0-9]+)?)\b/)
                            (Html.encode))));

Perhaps the gaps in the first column could be filled in the implementations?

Good idea!

@semmel, we addressed the formatting issue in sanctuary-js/sanctuary#438. To me (three years later), this is readable:
var incCount = ifElse (R.has ('count'))
                      (R.over (R.lensProp ('count'))
                              (R.inc))
                      (R.assoc ('count')
                               (1));

One more example:
//    highlightChunk :: String -> Html
const highlightChunk =
def ('highlightChunk')
    ({})
    ([$.String, Html.Type])
    (syntax ('keyword')
            (/\b(const|else|function|if|instanceof|new|return|this)\b/)
            (syntax ('boolean-literal')
                    (/\b(false|true)\b/)
                    (syntax ('number-literal')
                            (/\b([0-9]+(?:[.][0-9]+)?)\b/)
                            (Html.encode))));

Perhaps the gaps in the first column could be filled in the implementations?

Good idea!

@davidchambers:

Why not drop support for subtract (7, 3) and require subtract (3) (7)?

I'd like to do this, to go strictly unary everywhere.1  But I think that wanders far from the expectations of what Ramda is.
I've been thinking of what I'd want to do in a successor library., and this is definitely something I'd  prefer to include.
As to your concern @semmel, about layout, I've taken to writing most of my non-Ramda code in a fully curried format, and this looks totally normal to me:
const incCount = ifElse
    (has ('count'))
    (over (lensProp ('count')) (inc))
    (assoc ('count') (1))

But I really am thinking more about a successor to Ramda than about changes to Ramda itself.  The large userbase makes it less appealing to radical changes, even at a major version.
Also, I really like that table, and it would be nice to fill in some gaps.

1 I know that the callback to reduce and maybe one or two other places might still end up being exceptions to maintain compatibility with FantasyLand.  Either that or there's some other delegation strategy for FantasyLand.  But that latter seems doable now.

@davidchambers:

Why not drop support for subtract (7, 3) and require subtract (3) (7)?

I'd like to do this, to go strictly unary everywhere.1  But I think that wanders far from the expectations of what Ramda is.
I've been thinking of what I'd want to do in a successor library., and this is definitely something I'd  prefer to include.
As to your concern @semmel, about layout, I've taken to writing most of my non-Ramda code in a fully curried format, and this looks totally normal to me:
const incCount = ifElse
    (has ('count'))
    (over (lensProp ('count')) (inc))
    (assoc ('count') (1))

But I really am thinking more about a successor to Ramda than about changes to Ramda itself.  The large userbase makes it less appealing to radical changes, even at a major version.
Also, I really like that table, and it would be nice to fill in some gaps.

1 I know that the callback to reduce and maybe one or two other places might still end up being exceptions to maintain compatibility with FantasyLand.  Either that or there's some other delegation strategy for FantasyLand.  But that latter seems doable now.

I know that the callback to reduce and maybe one or two other places might still end up being exceptions to maintain compatibility with FantasyLand.

No such exception is necessary. S.reduce takes a curried binary function but provides an uncurried binary function when invoking fantasy-land/reduce. R.reduce could do the same.

I know that the callback to reduce and maybe one or two other places might still end up being exceptions to maintain compatibility with FantasyLand.

No such exception is necessary. S.reduce takes a curried binary function but provides an uncurried binary function when invoking fantasy-land/reduce. R.reduce could do the same.

One more example:
//    highlightChunk :: String -> Html
const highlightChunk =
def ('highlightChunk')
    ({})
    ([$.String, Html.Type])
    (syntax ('keyword')
            (/\b(const|else|function|if|instanceof|new|return|this)\b/)
            (syntax ('boolean-literal')
                    (/\b(false|true)\b/)
                    (syntax ('number-literal')
                            (/\b([0-9]+(?:[.][0-9]+)?)\b/)
                            (Html.encode))));

It took me a hot minute to realized what was going on here -- it's very interesting approach. I already feel like I'm swimming up stream trying to build functional libraries for the general community; Ramda has the benefits of being easy to pick up.
I'll have to experiment with this syntax on a personal project.

One more example:
//    highlightChunk :: String -> Html
const highlightChunk =
def ('highlightChunk')
    ({})
    ([$.String, Html.Type])
    (syntax ('keyword')
            (/\b(const|else|function|if|instanceof|new|return|this)\b/)
            (syntax ('boolean-literal')
                    (/\b(false|true)\b/)
                    (syntax ('number-literal')
                            (/\b([0-9]+(?:[.][0-9]+)?)\b/)
                            (Html.encode))));

It took me a hot minute to realized what was going on here -- it's very interesting approach. I already feel like I'm swimming up stream trying to build functional libraries for the general community; Ramda has the benefits of being easy to pick up.
I'll have to experiment with this syntax on a personal project.

@davidchambers:

I know that the callback to reduce and maybe one or two other places might still end up being exceptions to maintain compatibility with FantasyLand.

No such exception is necessary. S.reduce takes a curried binary function but provides an uncurried binary function when invoking fantasy-land/reduce. R.reduce could do the same.

Right, that's what I meant by the next sentence:

Either that or there's some other delegation strategy for FantasyLand.

There is still an issue for other delegation.  Which format would Ramda apply to an arbitrary object that has a reduce function.  I know that this is not an issue that Sanctuary has to worry about.  But Ramda has always been more ... let's say promiscuous ... about its delegation.

@davidchambers:

I know that the callback to reduce and maybe one or two other places might still end up being exceptions to maintain compatibility with FantasyLand.

No such exception is necessary. S.reduce takes a curried binary function but provides an uncurried binary function when invoking fantasy-land/reduce. R.reduce could do the same.

Right, that's what I meant by the next sentence:

Either that or there's some other delegation strategy for FantasyLand.

There is still an issue for other delegation.  Which format would Ramda apply to an arbitrary object that has a reduce function.  I know that this is not an issue that Sanctuary has to worry about.  But Ramda has always been more ... let's say promiscuous ... about its delegation.

I just want to say that not only does it lead to some really unintuitive to read code, but I actually can't even work it out in my head to begin with. I'm trying to do something super basic (if thing is greater than 1, thing-- else other thing), and I'm in the REPL and I still can't work it out! Isn't lte the opposite of gt? Never mind... probably just a blind spot in my particular mind.
I'm going ahead with the placeholder idea (gt(__, 1), but I still think it looks ugly. Was hoping there'd be an alternative in Ramda Adjunct, but I can't find one.

@pipedreambomb, if you're willing to add another dependency you could use S.gt:
> S.filter (S.gt (1)) ([0, 1, 2, 3, 4])
[2, 3, 4]

@pipedreambomb, if you're willing to add another dependency you could use S.gt:
> S.filter (S.gt (1)) ([0, 1, 2, 3, 4])
[2, 3, 4]

Thanks, I'll think about it. I think it might get confusing, mixing and matching similar libraries, but on the other hand, it's just a personal project, so I might be able to keep it straight. Might mess up my nice VS code auto-completes that automatically import the Ramda functions I want though, having another library with similar names for functions.

I'm going ahead with the placeholder idea (gt(__, 1), but I still think it looks ugly.

Indeed. I just drop point-free style in favour of x => x > 1. I guess, had there been ES6 arrow functions, gt, lt, and their likes would have never made it into Ramda.

I guess, had there been ES6 arrow functions, gt, lt, and their likes would have never made it into Ramda.

Ramda half-heartedly supports Fantasy Land, but in a library that embraces Fantasy Land these functions are far more versatile than their equivalent operators:
> S.lte ([1, 2, 3]) ([1, 2])
true

> S.lte ([1, 2, 3]) ([1, 3])
false

> S.filter (S.lte (S.Just (2))) ([S.Nothing, S.Just (1), S.Just (2), S.Just (3)])
[Nothing, Just (1), Just (2)]

I'm going ahead with the placeholder idea (gt(__, 1), but I still think it looks ugly.

Indeed. I just drop point-free style in favour of x => x > 1. I guess, had there been ES6 arrow functions, gt, lt, and their likes would have never made it into Ramda.

I like that better, actually, good idea. I kinda get lost in the "point-free or die" mentality of a new convert. Idiomatic or idiotic, I guess you could also call it :P


Create and maintain "develop" branch

With the impending release of 0.5, this issue is a reminder to split a develop branch from master per previous discussion. Use the repository architecture discussed in this article as a guide. Basically, master should no longer contain new untested code from PR merges. The develop branch will be used for unvetted code. In the near future, any clones of the master branch should ideally be expected to compile/link successfully and run with some degree of stability.

This makes sense.

Done.


How to center wrap panel and left align items

We recently updated from 1.5.8 to 2.0.4 (now 2.0.5) and we noticed that when there aren't enough items to fill the space the items are now centered in the screen. I've tried adjusting the horizontal alignment of the ListView and the containing Grid with no luck. Is there a way to left align the wrap panel and still have the panel itself centered in the Grid? In 1.5.8 this behavior worked as expected. I'm just not sure what to change to fix this.
Basically I want the wrap panel itself to be centered (so there is even margin on both sides) but if there's only a few items and not enough to take up the available width those items should be left aligned. I'm able to achieve something similar to this with a converter that sets the width of the listview to a proportion of the ActualSize of the containing element. However, when I do this the items are no longer centered. If I change the StretchItems property to true it gets close to what I want but there's too much space between the items (maybe there is a way to set this somewhere that I'm just not seeing?).
On a different note, thank you so much for creating this project because we really needed a wrap panel but when we use the built in one our app can crawl to a slow depending on of the amount of items in it.
Version Info
Package Version: 2.0.5
.NET Version: net8.0-windows
OS Version: Windows 11 22631.3296
<Style x:Key="DashboardListViewStyle" TargetType="{x:Type ListView}">
    <Setter Property="Margin" Value="0,0,0,12" />
    <Setter Property="HorizontalAlignment" Value="Stretch" />
    <Setter Property="Background" Value="#00FFFFFF" />
    <Setter Property="BorderBrush" Value="#00FFFFFF" />
    <Setter Property="ItemContainerStyle" Value="{DynamicResource DashboardListViewItemStyle}" />
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <vwp:VirtualizingWrapPanel AllowDifferentSizedItems="False"
                                           CanVerticallyScroll="True"
                                           ItemSize="328,440"
                                           MouseWheelDelta="48"
                                           Orientation="Horizontal"
                                           ScrollLineDelta="16"
                                           SpacingMode="None"
                                           StretchItems="False" />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="VirtualizingPanel.VirtualizationMode" Value="Standard" />
    <Setter Property="VirtualizingPanel.ScrollUnit" Value="Pixel" />
</Style>

If I understand you issue correctly, it should be sufficient to set the SpacingMode to StartAndEndOnly. Keep in mind that this only works properly when AllowDifferentSizedItems is false.
I hope that helps, otherwise please provide more information e.g. screenshots or some minimal sample.

That fixed it. Thank you for the help!


Checkboxes / Radio buttons don't vertically align with label text when using a custom font size

Create a customized bootstrap with font-size 20px being the only change.
Any input type checkbox/ radio with label text is viably not aligned
Seems like the generated margin is
input[type="radio"],
input[type="checkbox"] {
  margin: 4px 0 0;
  margin-top: 1px \9;
  line-height: normal;
}

regardless of the base font size
Here is an example :

margin probably needs to be calculated based on font size...

Agreed we need to set them by font size, but I'm hesitant to make any changes to v3 to support that just yet. I know it sucks, but for now you'll need to customize that yourself. v4 will have proper scaling of things by typography.

@mdo, is it difficult to send a fix about this issue to a next minor version of Bootstrap 3?

there won't be any new major nor minor versions of Bootstrap 3. all efforts are now focused on version 4, I'm afraid.

@patrickhlauke , so what's about bug fixes? This can be thought as a bug, I think.

I have found a solution:
// Position radios and checkboxes more better
input[type="radio"],
input[type="checkbox"] {
	margin-top: ((@line-height-base - 1)/2) * 1em;
	width: 1em;
	height: 1em;
}

This solution is not only care about font-size, also line-height. Some examples: https://jsfiddle.net/r0m7a2kj/

This bug is also present in v4-beta1.


Buttons in Camera Rolle have no function

See The Screenshot below

Android App Version 2.5.3

long press on list items you want to work on, then the buttons will be activated.

No, that is just not the case.
Even a long press on an entry only turns the keys black, but they still don't work.
What function should the left button have?
It's black, but it doesn't work either.
For my understanding it should close the overview list again.

Re-produced this bug on development machine. It's related to recent change on action bar management. When bottom sheet is fully expanded, the function button area on the top is actually cover by a transparent action bar, they are not responding to clicks.

fix is on the way

Ok cool
then I am curious 👍


[cloud_firestore] Indexes missing messages should be shown at the console

I wasted a lot of time on a query that just didn't work, and sometimes (don't as me how) worked but super slow. I didn't think it was a missing Composite Index, since if there's a missing one the Cloud Firestore docs say there would be a message on the console.
After a while I got the idea that maybe it was a missing index and the error message was being printed in Logcat but not on the Flutter Debug Console. Lo and Behold, the message was there.
The perfect solution would be to print the error messages on the Flutter Console, but for now, at least the docs, specially the Getting Started, should point out that any messages related to indexes missing will be printed to Logcat (I don't know the equivalent for iOS).

I'm having this same issue, and it took me a lot of time to figure out it was the problem. Please fix this!!

Consolidating under #1223 - we'll be looking at parsing native error messages & codes and bubbling these up to the Dart layer in a consistent cross-platform format.


[RTE][Draft] Storybook update for rich text edit box

What

Storybook update for rich text edit box. This PR can be merged only after beta release.
Why

How Tested

Storybook
Process & policy checklist

[x] I have updated the project documentation to reflect my changes if necessary.
[x] I have read the CONTRIBUTING documentation.

Is this a breaking change?

[ ] This change causes current functionality to break.

Also is the rich text editor on by default for the messageThread preview?

Should this banner be at the top of the page? Or on each section?

Also is the rich text editor on by default for the messageThread preview?

Should this banner be at the top of the page? Or on each section?

Fixed


Add river stage graphs

I guess that's still on the TODO list?

Yes, Michael is going to provide completely new SVGs with more water lines (so cross-section also shows flooding).


Multiple Service Account

Feature request
We need to set up multiple ServiceAccount for different services such as GitHub, Private Registry, etc. but we can only configure one ServiceAccount in each PipelineRun
Use case
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  generateName: my-pipeline-
spec:
  serviceAccountNames:
    - serviceaccount-buildpacks
    - serviceaccount-github
  pipelineRef:
    name: my-pipeline
  params:
    - name: private-registry-url
      value: https://parlacom.harbor.com/parla
    - name: repo-url
      value: https://github.com/parlacom/tekton.git
    - name: revision
      value: main
  workspaces:
    - name: shared-data
      persistentVolumeClaim:
        claimName: pvc-tekton-claim

This is not technically possible, at least from the Kubernetes point of view. A Pod can only have one ServiceAccount and this, the same is true for a TaskRun. That said, for PipelineRun you can already specify multiple service account, but "attached" to a given Task, see here.

Thanks @vdemeester, really appreciate your comments. I followed the example and it worked fine.

@parlacom I think we can close that issue then, am I right ? 👼🏼

Hi @vdemeester
i have same requirements

I have a git clone task from private repo, so i have created service account and i added service account name inside run.yaml its working file as we expected.
Having another task kuberentes-action which will setup kube cofig file to connect to the GKE cluster, for this i have created another service account because if not create genrally tekton pipeine line will get error message like this.

deployments.apps "java" is forbidden: User "system:serviceaccount:devops-caas-maven:bitbucket-sa-git-clone"
cannot get resource "deployments" in API group "apps" in the namespace "devops-caas-maven"

To avoid this i have created service account and i added into run.yaml like this.
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  generateName: kube-test
  namespace: devops-caas-maven
spec:
  serviceAccountName: bitbucket-sa-git-clone
  pipelineRef:
    name: kubernetes
  workspaces:
    - name: shared-workspace
      persistentvolumeclaim:
        claimName: maven-source-pvc

But git clone will always will be success  but kubernetes-action task will getting failed with below error
from server for: "/workspace/shared-workspace/source/k8s/deployment.yaml": deployments.apps "java" is forbidden: User "system:serviceaccount:devops-caas-maven:bitbucket-sa-git-clone" cannot get resource "deployments" in API group "apps" in the namespace "devops-caas-maven"

Can you please help me, is that service can be manage with task level ? because https://tekton.dev/docs/pipelines/pipelineruns/#mapping-serviceaccount-credentials-to-tasks this page having mapping with single service account name.


Enable the rest of the model tests

These were disabled before the code was open source. With more resources on CircleCI, we should be able to re-enable this)

Self-assigning.

Closed in #63 (basically).


Add prominent "Submit your paper" buttons to the front and CFP pages

To encourage paper submissions (and to make it easy for people to find the submission portal) I think it would be good to add a prominent "Submit your paper" button to the front page of https://www.chilconference.org/.
The link should also be added prominently at: https://www.chilconference.org/call-for-papers.html

I've added a button to the CFP page. @tompollard - can you confirm this is what you had in mind?
@briangow / @kperros / @corcra - can you add a similar button to the Home page between "CHIL 2022" and "Contact US"?

thanks @tnaumann, looks good to me!

This was resolved with #113


Mark orders complete in POS

POS can't mark orders as complete

POS now has a link to individual order where orders can be marked complete