These are chat archives for ramda/ramda

6th
Aug 2017
Rafi
@Rafi993
Aug 06 2017 03:13
@cilquirm could you post the sample input you are trying to transform
Aadi Deshpande
@cilquirm
Aug 06 2017 03:19
@Rafi993
{
  id: 12345,
  props: {
     name: 'Test',
     terms: [ { id: 1, val: 'term1' }, { id: 2, val: 'term2' } ],
     entities: [ { id: 25, val: 'Boston' }, { id: 33, val: 'Fenway Park' } ]
  }
}
basically i have to pull out the first term and first entity
and i was trying to create a DRY mechanism to specify the path
Dustin Stiles
@dustinws
Aug 06 2017 03:41

@rickmed Thanks for the response!
I'm aware you can flatten the promises down. That could easily be represented as R.pipeP(getA, getAB, getABC)

Here is the problem.

R.pipeP(getA, getAB, getABC)('').then((value) => {
  // Here, value is the final result, ABC
  // I need access to A, B, and ABC
})

I wasn't nesting the promises so that they would run sequentially, instead, I was nesting them so that I have references to A, AB, and ABC all in the same function body. Notice how in my example, the final function receives all of the intermediate steps, not just the final value.

Hope that clarifies!

Dustin Stiles
@dustinws
Aug 06 2017 03:49

@rickmed
Just to show a quick example of how this could be used. It's basically my use case, but since it's work code, I'm not at liberty to post the real thing.

// :: a -> Promise User
const findUser = () => {...};
// :: User -> Promise Post
const findLastPost = user => {...};
// :: Post -> Promise [Comment]
const findComments = post => {...};

const doSomethingFancy = (user, lastPost, comments) => {
  // Do something with all three.
};

// Now you can do this.
R.pipeP(
  pipeScan(findUser, findLastPost, findComments),
  R.tail, // Get rid of 'undefined' at the beginning
  R.apply(doSomethingFancy));

If I were to flatten everything down, or use pipeP, then I would only have access to the comments array at the end.

Rick Medina
@rickmed
Aug 06 2017 04:34
@dustinws I see -sorry it seems I had some caffeine deficit. I'd probably have written it very similarly. There's definitely not an out of the box equivalent function in ramda or cookbook https://github.com/ramda/ramda/wiki/Cookbook
Dustin Stiles
@dustinws
Aug 06 2017 05:02
@rickmed No worries, I really appreciate you trying to help!
I think it's kind of cool, but I highly doubt I'm the first one to think of it. I was hoping it existed somewhere in the library, or even in another (probably more functional ) language.
Kurt Milam
@kurtmilam
Aug 06 2017 12:25
Any ideas how an implementation of assoc that works on functions might look?
const id = x => x
id.aProperty = 'a value'
id.myNameIs = 'id'
const identity = R.assoc( 'myNameIs', 'Identity', id )
id.myNameIs //-> 'id'
id.aProperty //-> 'a value'
identity.myNameIs //-> 'Identity'
identity.aProperty //-> 'a value'
Kurt Milam
@kurtmilam
Aug 06 2017 12:36
And, in case it wasn't clear:
identity(1) //-> 1
Adam Szaraniec
@mimol91
Aug 06 2017 12:53

@kurtmilam

const R_assoc = (key, val, fn) => {
  let result = fn.bind({});
  result[key] = val;

  return result;
}

Like that ?

Gabe Johnson
@gabejohnson
Aug 06 2017 13:17
@dustinws your use case is covered by async functions. In a language like Haskell or PureScript would use do notation.
Fluture is a Future lib that fakes do using generators. https://github.com/fluture-js/Fluture/blob/master/README.md#do
Bijoy Thomas
@bijoythomas
Aug 06 2017 13:19
@mimol91 findIndex returns -1 if it cannot find something that matches the predicate and in your pipeline, a mismatched Id will always find the 0th element
I may be wrong but maybe its a good use case for Just/Nothing?
pipe(
  findIndex(e => e.id === Id),
  idx => idx >=0 && idx <= length(elements) - 2? Just(idx) : Nothing(),
  chain(compose(
    e => e.use? Just(e) : Nothing(),
    flip(prop)(elements),
    inc
  ))
)(elements)
Adam Szaraniec
@mimol91
Aug 06 2017 13:46

hmm its not point free :(
I was able to to make sth like

R.converge(
  R.nth, [
    R.pipe(
      R.findIndex(propEq('id', Id)),
      R.inc
    ), 
    R.identity],
  R.ifElse(
    (el) => (el.use),
    R.identity,
    R.always(null),
  )
)(elements)

but its sill I dont like it , I m not used to converge ;/ Any clue if its possible to use chain instead?

Kurt Milam
@kurtmilam
Aug 06 2017 13:49
@mimol91 result loses all of the other properties on fn in your example and calling the function on an already assoc'ed fn doesn't work correctly, but thanks for the suggestion :) :
const fn = x => x
fn.a = 1
fn.b = 2
const fn2 = R_assoc( 'a', 3, R_assoc( 'a', 2, fn )  )
fn2.a //-> 2 but should be 3
fn2.b //-> undefined but should be 2
Adam Szaraniec
@mimol91
Aug 06 2017 13:50
On the beginning my mind just blown, because I see for first time to set properties on function. Is there any use-case for it ?
Kurt Milam
@kurtmilam
Aug 06 2017 13:53
Yes, my use-case is a little complicated to explain, but it involves maintaining a call stack, of sorts.
Adam Szaraniec
@mimol91
Aug 06 2017 13:57
fn2.a //-> 2 but should be 3 .
Are you sure? its 3
const R_assoc = (key, val, fn) => {
  const result = fn.bind({});
  result[key] = val;

  return result;
}

const fn = x => x
fn.a = 1
fn.b = 2
const fn2 = R_assoc( 'a', 3, R_assoc( 'a', 2, fn )  )

console.log(fn2.a)  -> 3
Nvm,b is still missing :(
Kurt Milam
@kurtmilam
Aug 06 2017 14:03
Apologies, you're right that fn2.a //-> 3. I must have been sloppy in my testing.
Dustin Stiles
@dustinws
Aug 06 2017 14:11

@gabejohnson Right, it would look like this I think

main blank = do
  A <- getA blank
  AB <- getAB A
  ABC < getABC AB
  doSomethingFancy blank A AB ABC

I'd love to use the generator syntax with, but unfortunately I haven't been able to win over everyone at work. I think everyone is waiting on async/await
I still haven't lost hope on getting FL implementations into that codebase though, I'm determined :wink:

Kurt Milam
@kurtmilam
Aug 06 2017 14:16
@mimol91 I wrote a cloneFn function, instead. I think that will do the trick: https://goo.gl/fCgcLh
Dustin Stiles
@dustinws
Aug 06 2017 14:17

@gabejohnson I'm surprised haskell doesn't have a function for this though (unless you're not claiming that, then apologies). It's very similar to something like liftA3, where the input types are scanned with composition.

I'm definitely no haskell expert, but usually I find that whenever I think I've done something cool, haskell has already done it / named it.

Another reason this kind of bums me out is naming. pipeScan doesn't sound right to me, I was really hoping for something "legitimate" from another FP language. Any suggestions on another name, assuming this is general enough to even warrant a name?

Adam Szaraniec
@mimol91
Aug 06 2017 14:26

@kurtmilam
Isnt better to use object.entries?

Object.entries(fn).forEach(([key, val]) => {
        result[ key ] = val;
  })

You can get rid of keyVals

Kurt Milam
@kurtmilam
Aug 06 2017 14:29
Not wide enough browser support for Object.entries
I had forgotten to set the __cloned and __originalFn properties: https://goo.gl/RwmWZH
Rick Medina
@rickmed
Aug 06 2017 14:51
@gabejohnson don't you find his solution very in the spirit of fp? do notation is just imperative sugar for the lambda base expression after all... I'm only a beginner in haskell but couldn't you do something similar composing fold and bind (for n list of IOs)? @dustinws
Gabe Johnson
@gabejohnson
Aug 06 2017 19:20
@rickmed @dustinws I think scanP has more value than pipeScan as it's more general and pipeScan has a trivial implementation in terms of it
Rick Medina
@rickmed
Aug 06 2017 20:23
@gabejohnson :+1: @dustinws