These are chat archives for ramda/ramda

7th
Sep 2016
Keith Alexander
@kwijibo
Sep 07 2016 07:21
re ramda/ramda#1869 (deprecate composeP) fwiw, I don't have a principled objection to Ramda providing bridging functions that let you use non-functional parts of js in a functional way, but I stopped using pipeP/composeP because of the awkwardness of composing in error handling
Keith Alexander
@kwijibo
Sep 07 2016 07:26
perhaps I missed a trick, but it seemed like I had to do
const catchP = f => p => p.catch(f)
const doSteps = pipe(
    pipeP(
        step1,
        step2
     ),
    catchP(e=>console.error("Couldn't doSteps", e))
)
which doesn't seem to have much advantage to me over, eg:
const doSteps = xs =>
     step1(xs)
     .then(step2)
     .catch(e=>console.error("Couldn't doSteps", e))
Andrea Scartabelli
@ascartabelli
Sep 07 2016 09:02
@kwijibo The advantage of functional composition is being able to describe computations, instead of executing them, by building new tools from existing ones. If you aren't going to reuse what you have built there's little to no advantage, as per your example.
Julien Goux
@jgoux
Sep 07 2016 11:41
Hi
Alastair Hole
@afhole
Sep 07 2016 16:28
Hi all - is there a neat way to get a property from an object (ala propOr) with the default being a different property on that object as opposed to a value passed explicitly to propOr? Hope that makes sense...
Kurt Milam
@kurtmilam
Sep 07 2016 16:33
I'm trying to get a point-free version of this:
x => contains(prop('name', x), ['bob', 'sue', 'ann'])
But I'm stuck. What's the simple solution I'm overlooking?
Brad Compton (he/him)
@Bradcomp
Sep 07 2016 16:35
@afhole check out
R.either
Brad Compton (he/him)
@Bradcomp
Sep 07 2016 16:36
Note that the functions don't have to return a boolean
Alastair Hole
@afhole
Sep 07 2016 16:36
@Bradcomp Ahh cool, I think I dismissed either on that basis but if it can return the prop value that sounds dandy :)
Brad Compton (he/him)
@Bradcomp
Sep 07 2016 16:38
@ram-bot
compose(flip(contains)(['bob', 'sue', 'ann']), prop('name'))({name: 'ann'})
ram-bot
@ram-bot
Sep 07 2016 16:38
true
Kurt Milam
@kurtmilam
Sep 07 2016 16:40
@Bradcomp Thanks - I had considered something along those lines, but figured there might have already been something like flip(contains) available in the library.
Brad Compton (he/him)
@Bradcomp
Sep 07 2016 16:40
Well, you can also use the placeholder, but I hear that placeholder support is changing
Alastair Hole
@afhole
Sep 07 2016 16:43
@Bradcomp either( prop('a'), prop('b') ) works great, thank you
Brad Compton (he/him)
@Bradcomp
Sep 07 2016 16:43
:+1:
Kurt Milam
@kurtmilam
Sep 07 2016 16:43
Thanks - I had toyed with using the placeholder as well. Glad to see I wasn't totally off-track. Thanks!
Kurt Milam
@kurtmilam
Sep 07 2016 17:43
Tips on getting to a point free version of this?
const allExpressions = expression =>
  append(
    fromPairs([
      ['type', prop('type')(expression)]
      , ['expression', either(path(['path', 'original']), prop('original'))(expression)]
    ])
    , compose(
      map(allExpressions )
    )(expression)
  )
expression has metadata and can have a list of sub expressions, so I get the metatata for the current expression, then map over any sub expressions by calling myself recursively.
Then I append the results to a single list that I flatten elsewhere, giving me a flat list of all expressions and their sub expressions.
Would I be better off generating a list of all expressions, then flattening it, then mapping over the flattened list in order to get the metadata of each expression in the list?
Kurt Milam
@kurtmilam
Sep 07 2016 17:56
I stripped some code out of the example to simplify it, but I see I may have stripped out too much. The compose is actually more like this:
compose(
  map(allExpressions )
  ,  subExpressions
)(expression)
Travis LaDuke
@laduke
Sep 07 2016 18:08
R.set doesn't create a property if it doesn't exist...
What should I do?
nevermind. It does.
Drew
@dtipson
Sep 07 2016 21:11
raised this issue once before, but when compose is run with no arguments... 1. lodash _.flowRight and redux's compose both return identity 2) underscore's _.compose returns a function that when called will return a cryptic error, and 3) Ramda's compose immediately throws a helpful error. I don't know if there's any "right" answer there (though 2 seems like a wrong answer) but I also have a feeling that 1 makes the most sense. If only because identity is the "empty" element in composition for Endo. And because it means that if you have a list of functions that you dynamically add or subtract from, a compose that returns identity as a base case requires no special handling or protective code.
Brad Compton (he/him)
@Bradcomp
Sep 07 2016 21:15
1 can be an issue if your right-most function takes more than one argument though.
I mean, if you attempt to pass in more than one argument ;-P
Because, of course, you don't have a rightmost argument if you have 0
Drew
@dtipson
Sep 07 2016 21:16
right, I think that's the callers special problem to sort out in such a case, not compose's
Imagine a composed operation that is built from functions that modify and return a matrix of values (like a bunch of pixel filters). You could see building an app that allowed each filter to be added or removed or re-ordered in a list, and then the transformation is simply compose(...list)(matrix)
If compose defaults to identity with an empty list, nothing special is needed to handle the case of an empty list of transformations
Brad Compton (he/him)
@Bradcomp
Sep 07 2016 21:20
I can definitely see the usefulness of that. In the case of lodash it would just work, while in the case of Ramda it would require the caller to provide the identity transformation explicitly
Drew
@dtipson
Sep 07 2016 21:23
For reference, the FL implementation of the Endo monoid, though I don't actually know if it should weigh into a standalone compose: https://github.com/fantasyland/fantasy-monoids/blob/master/src/endo.js
Travis LaDuke
@laduke
Sep 07 2016 22:40

How do you like:

 var lastWord = R.last(R.split(' ', sentence))

into

  var lastWord = R.last(R.split(' ', ??));
  lastWord('hello it's me');
LeonineKing1199
@LeonineKing1199
Sep 07 2016 22:40
You can use R.compose, I do believe.
const lastWord = R.compose(R.last, R.split(' '));
Travis LaDuke
@laduke
Sep 07 2016 22:42
Oh duh. I'm losing it. thanks.
LeonineKing1199
@LeonineKing1199
Sep 07 2016 22:43
There's also R.pipe if you happen to dislike the right-to-left flow of arguments
LeonineKing1199
@LeonineKing1199
Sep 07 2016 23:03
So, I've noted that reduce operates on anything iterable from a JS standpoint. I wonder if some of the other List-centric algorithms will begin to favor the iterable interface. For example, last right now is basically an alias for nth. I know it'd be incredibly inefficient when compared to types that support random access but you could also rewrite nth and subsequently last to support more generalized containers like Map, Set and any user-defined iterable types.
Paul
@pauloliver
Sep 07 2016 23:46
I'm too lazy to check the MDN right now, but do the built in Map and Set guarantee consistent iteration order? I know some implementations of those data structures don't.