These are chat archives for ramda/ramda

9th
Jan 2017
Tushar Mathur
@tusharmath
Jan 09 2017 08:46
is there a way to re-order argument for a function?
flip does it only for the first two
James Forbes
@JAForbes
Jan 09 2017 09:51

@tusharmath I don't think so, but you could use array methods to adjust the order of the args then you applyto call the function with those args

e.g. simple example


var reverseArgs = f =>
  R.pipe(
    Array.of
   ,R.reverse
   ,R.apply(f)
  )
Sudarsan Balaji
@artfuldev
Jan 09 2017 15:10
hi, so I'm a newbie to FP and was pointed to this community when I had some problems understanding how to think in functional terms.

I find it very hard to come up with a functional way to achieve something like:

  1. if all elements of an array are 0, return 0.
  2. if all elements of an array are 1, return Infinity.
  3. if all elements of an array are -1, return -Infinity.
  4. if all elements of an array are either 0 or 1, return number of 1s.
  5. if all elements of an array are either 0 or -1, return -1 * number of 1s.
  6. if all the above fail, return 0.

I understand I must use reduce (to obtain a single value from an array), but using a for loop, and maintaining a few variables this can be done in a single pass of the array, breaking from the loop as soon as a breaking condition is met (like 1,0,-1 can instantly return 0 instead of iterating through all the elements). How can I achieve this in pure FP?

It would be very educational for me. :)

Aldwin Vlasblom
@Avaq
Jan 09 2017 15:35
This function seems to do the trick, without keeping any state, in a single pass, breaking on the failure condition:
const f = input => {
  const o = addIndex(reduce)(
    (o, v, i) => Math.abs(o + v) < Math.abs(o) ? reduced(0) : o + v,
    0,
    input
  )
  return Math.abs(o) === input.length ? o * Infinity : o;
}
Might need a special case for empty array yet.
Aldwin Vlasblom
@Avaq
Jan 09 2017 15:59
Oh don't need addIndex
Sudarsan Balaji
@artfuldev
Jan 09 2017 16:31
I'm sorry, but I'm not able to follow what's going on. Can you please elaborate?
I want to know how it works, plus how it occurred to you to solve it in this particular way. The latter would help me in my journey towards FP. I find it difficult to think in functional terms
How it breaks early is also something I'd like to understand
Brenton Alker
@tekerson
Jan 09 2017 16:37
It's maybe not the best example to help you understand, since it's using a bit of math to avoid some of the logic you wanted to express - it works because you happened to pick 1 and -1.
It's reducing over the array by adding the number to a total, and saying - if the absolute value of the total is less than the previous iteration, then it's going in the wrong direction so exit early (because we have mixed 1's and -1s)
BasH
@bas080
Jan 09 2017 16:38
@artfuldev, there are books that might be worth your time. They can explain it much better than a chat session can.
Brenton Alker
@tekerson
Jan 09 2017 16:38
the early break is an (actually somewhat unusual) feature of Ramda's reduce - if the reducer function returns R.reduced it short-circuits the rest of the iterations.
Sudarsan Balaji
@artfuldev
Jan 09 2017 16:39
@tekerson that short circuit is indeed nifty
Brenton Alker
@tekerson
Jan 09 2017 16:40
it's nice, but it's really only an optimization - not an important part of the algorithm
Sudarsan Balaji
@artfuldev
Jan 09 2017 16:41
so in case I weren't using Rambda, how would I break early? In a reduce operation?
@bas080 I do understand. Would you be kind enough to share some good books that help me think in functional terms? The problem with seeing some problems in FP is that when I have a real problem I find it hard to translate it to an application in the FP paradigm
@tekerson thanks for the explanation, I'm able to follow the code now.
Brenton Alker
@tekerson
Jan 09 2017 16:44
in a similar way - you can have your reduce function return a specific "sentinel" value, then on each subsequent iteration check - is the accumulator this value, if so, just return it again. So, it still continues through every loop, but doesn't "do" anything any more.
Sudarsan Balaji
@artfuldev
Jan 09 2017 16:45
but the condition check for the sentinel value happens for the remaining iterations.
so the solution is to write a custom reduce function with an iteration with for loop inside, is it?
Brenton Alker
@tekerson
Jan 09 2017 16:46
yes, the check happens for the remaining iteration - which is why Ramda's feature is a nice optimization.
no, you don't need to write an iteration inside the reducer
Sudarsan Balaji
@artfuldev
Jan 09 2017 16:48
I meant like this:
var EXIT_REDUCE = {};

function reduce(a, f, result) {
  for (let i = 0; i < a.length; i++) {
    let val = f(result, a[i], i, a);
    if (val === EXIT_REDUCE) break;
    result = val;
  }
  return result;
}
Brenton Alker
@tekerson
Jan 09 2017 16:49
well, that's not a reduce, that's just an imperative loop inside a function called "reduce" :)
Sudarsan Balaji
@artfuldev
Jan 09 2017 16:49
and then give an f to this reduce method which returns EXIT_REDUCE when it wants to break early. RighT?
@tekerson yes. :(
Brenton Alker
@tekerson
Jan 09 2017 16:50
ah, actually, that's probably not too far off an implementation of a reduce function. but you don't need to write that - that's what R.reduce is doing for you.
Sudarsan Balaji
@artfuldev
Jan 09 2017 16:50
so I always imagined declarative was introducing an abstraction over imperatives and inside these filter, map, reduce etc functions there's always a for loop or such. Or am I deeply mistaken?
@tekerson yes I understand that.
Brenton Alker
@tekerson
Jan 09 2017 16:51
well.. in many cases there is, but the idea is, we don't care :)
again - it's an optimisation
and that's the advantage of using the abstraction
BasH
@bas080
Jan 09 2017 16:52
@artfuldev, it is about abstraction.
Sudarsan Balaji
@artfuldev
Jan 09 2017 16:52
@bas080 @tekerson yes, thank you
BasH
@bas080
Jan 09 2017 16:52
@artfuldev, the goal is to do very complex stuff by leveraging abstraction.
Sudarsan Balaji
@artfuldev
Jan 09 2017 16:53
just trying to widen my perspective here. so may I share a solution I formulated, when not knowing how to do this (break early), while desperately trying to stick to FP?
BasH
@bas080
Jan 09 2017 16:54
@artfuldev, If FP does not fit your frame of thought, you'r either using it incorrectly or it's just not the tool for you or for the specific use case.
Sudarsan Balaji
@artfuldev
Jan 09 2017 16:55
function evaluate(cells: Cell[]): number {
  const length = cells.length;
  if(length === 0) return 0;
  const initial = { undefined: 0, true: 0, false: 0 };
  const counts = cells.reduce((counts, cell) => increment(counts, cell), initial);
  if (counts.undefined === length) return 0;
  if (counts.true === length) return Infinity;
  if (counts.false === length) return -Infinity;
  if (counts.false === 0) return counts.true;
  if (counts.true === 0) return -counts.false;
  return 0;
}
here true and false are +1 and -1, undefined is 0
@bas080 just trying to learn something
@bas080 if I'm using it incorrectly, I need to learn to use it correctly, and I wouldn't make a judgement that it's not the tool for me so early in my journey towards learning it
function increment<T>(obj: T, key: any): T {
  const newObj = {} as T;
  for(let prop in obj)
    if(obj.hasOwnProperty(prop))
      newObj[prop] = obj[prop];
  newObj[key+'']++;
  return newObj;
}
so increment actually updates the 'undefined', 'true', or 'false' keys by incrementing the current value of that key
but the solution posted here is very elegant
BasH
@bas080
Jan 09 2017 16:58
@artfuldev, feel free to judge all you want. I do it all the time.
Sudarsan Balaji
@artfuldev
Jan 09 2017 16:59
@bas080 :)
@tekerson are you still here?
so breaking early was one of the things I found hard to know how to do. now I kind of get that
and with rambda, it's even easier
I had a difficult time wrapping my head around another problem I was trying to solve.
finding it difficult to put it in words as a generic problem.
let me try to come up with something on my own a little while longer.
Sudarsan Balaji
@artfuldev
Jan 09 2017 17:04
@bas080 any book recommendations for me? say a complete newbie who wants to learn how to think in FP terms
BasH
@bas080
Jan 09 2017 17:06
@artfuldev, To get into the mindset I would start with JavaScript Allongé, the "Six" Edition.
Sudarsan Balaji
@artfuldev
Jan 09 2017 17:06
@bas080 thank you :)
Gleb Bahmutov
@bahmutov
Jan 09 2017 17:07
Second "JavaScript Allonge" - plus it is free to read online
Sudarsan Balaji
@artfuldev
Jan 09 2017 17:07
@bahmutov cool to see you here :)
Gleb Bahmutov
@bahmutov
Jan 09 2017 17:07
other book suggestion: functional javascript https://glebbahmutov.com/blog/javascript-books/#advanced-books
:)
Sudarsan Balaji
@artfuldev
Jan 09 2017 17:08
is there a kindle version? much prefer to read there
Gleb Bahmutov
@bahmutov
Jan 09 2017 17:08
honestly, I don't know, I think yes, since it is an ebook
I suggest reading in parallel with coding small examples on computer
Sudarsan Balaji
@artfuldev
Jan 09 2017 17:09
good to know. will do that.
thanks
BasH
@bas080
Jan 09 2017 17:11

@bahmutov, functional javascript is quite enjoyable.

I also liked https://github.com/MostlyAdequate/mostly-adequate-guide.

Gleb Bahmutov
@bahmutov
Jan 09 2017 17:14
oh, absolutely the Mostly adequate guide and the egghead.io video course
Gabe Johnson
@gabejohnson
Jan 09 2017 17:14
Hey @artfuldev!
Sudarsan Balaji
@artfuldev
Jan 09 2017 17:15
hi @gabejohnson
thanks! :)
Gabe Johnson
@gabejohnson
Jan 09 2017 17:15
an overwhelming number of resources there
Sudarsan Balaji
@artfuldev
Jan 09 2017 17:16
I'm going to have my hands full for quite some time now, ain't I? LOL :)
good, good.
no dearth of good resources
Gleb Bahmutov
@bahmutov
Jan 09 2017 18:22
Another good book - half off today https://twitter.com/luijar/status/818523279484973056
Gabe Johnson
@gabejohnson
Jan 09 2017 22:25
@JAForbes have you checked out https://github.com/calmm-js/partial.lenses
James Forbes
@JAForbes
Jan 09 2017 23:35

@gabejohnson yeah actually I saw that yesterday (had a lens research day), it looks really cool. Have you used it?

I ended up going with ramda-lens's iso because I'm trying to keep code size small for what I have in mind.