These are chat archives for ramda/ramda

10th
Jan 2017
Gabe Johnson
@gabejohnson
Jan 10 2017 01:19
@JAForbes haven't tried it yet. Same guy wrote a zipper lib I've been using
James Forbes
@JAForbes
Jan 10 2017 01:34
wow, I've never seen this. Is there some theory I can read up on for zippers that you know of @gabejohnson ?

ah there's this at the bottom of the readme: http://michaeldadams.org/papers/scrap_your_zippers/

Thanks for the resources @gabejohnson :D

Gabe Johnson
@gabejohnson
Jan 10 2017 02:06
@JAForbes np. I first saw zipper in Clojure. They’re pretty nifty for tree traversal
James Forbes
@JAForbes
Jan 10 2017 02:11
Clojure's full of great ideas
Gabe Johnson
@gabejohnson
Jan 10 2017 02:12
truth
hemanth.hm
@hemanth
Jan 10 2017 04:19
@gabejohnson Would it make sense for fastener to fail silently on TypeError: Cannot read property 'focus' of undefined?
Hardy Jones
@joneshf
Jan 10 2017 09:49
@JAForbes the problem with most of those "iso"s you showed a few days ago are they they aren't really isos at all. For instance, since parseJSON can fail in json, you really have more of a prism than an iso. Similarly for parseInt in number and I'd imagine that that replace somehow doesn't work properly for pixels either (maybe if 'px' is elsewhere in the string).
This is almost always a problem when working with a primitive type.
Also, the best theory for zippers comes from Huet's functional pearl.
Hardy Jones
@joneshf
Jan 10 2017 09:55
The code is in OCaml, so if you're familiar with an ML it should be understandable (I don't think it uses any OCaml specific features).
Lists have a slight difference from SML, [1;2;3] vs [1,2,3].
James Forbes
@JAForbes
Jan 10 2017 10:01
@joneshf yeah great point, thanks for the post, somewhere good I can read about prisms too?
Hardy Jones
@joneshf
Jan 10 2017 10:03
@artfuldev I think there's a good deal of conflation between functional programming and declarative programming. The two are not the same. You show this in your evaluate function here: https://gitter.im/ramda/ramda?at=5873c069873d96e16d46f91a That is functional programming at its finest. But it's not declarative programming. You've written an imperative functional program. There is absolutely nothing wrong with this! You can write imperative FP, declarative FP or both. The point I'm trying to make is that you already know how to do FP just fine :), and it sounds like what you're searching for is declarative programming.
@JAForbes unfortunately, I don't have any good links.
Especially not for the van Laarhoven kind.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:07
@joneshf I can say I'm beginning to understand that. Thanks for directing me to it. I used to think declarative is the only functional way. But I can see there is also something called imperative FP, from what you mentioned. I very much dislike having for or while loops in my code which kind of make it difficult to follow what is happening (thereby why).
i tried to break my problem down into functions, which can be reused, and operate on immutable data
but i was not satisfied
also the problem of breaking early
James Forbes
@JAForbes
Jan 10 2017 10:08
@joneshf :)
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:09
@joneshf if possible, would you have the time, patience, and kindness helping me with another problem?
it involves while, and jumping over indices, and I'm finding it difficult to do (declartively) functionally
but I would like to know how to do it
Hardy Jones
@joneshf
Jan 10 2017 10:11
@artfuldev I can certainly try :)
BasH
@bas080
Jan 10 2017 10:11
@joneshf, FP really shines because of the composability in my opinion. Which is only achieved by finding the right abstraction.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:12
thank you
@bas080 feel free to help me out here as well
although i think this might be an unfamiliar syntax. this is C#
private static int GetNumberOfTransmitters(IEnumerable<int> houseLocations, int coverageLength)
{
    var distinctSortedHouseLocations = houseLocations.OrderBy(x => x).Distinct().ToList();
    if (distinctSortedHouseLocations.Count == 1) return 1;
    var count = 0;
    var current = 0;
    while (current < distinctSortedHouseLocations.Count)
    {
        var transmitterIndex = GetNextTransmitterIndex(distinctSortedHouseLocations, current, coverageLength);
        count++;
        current = GetNextNonCoveredHouseIndex(distinctSortedHouseLocations, transmitterIndex, coverageLength);
    }
    return count;
}
Hardy Jones
@joneshf
Jan 10 2017 10:12
C# is fine.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:13
here's the problem:
i have a list of houses located at certain places (numbers from 1 to 10^5, say)
i have transmitters of range coverageLength
meaning if i place a transmitter at 2 with coverage length 1, the transmitter covers 1,2,3 (2-1, 2, 2+1)
given the locations of houses in an area, and a coverage length, i want the minimum number of transmitters which can cover the houses
this is a problem on hacker-rank. I have solved it.
but evidently not using (declarative) FP
and I want to know how to do that
and the thought process involved
Hardy Jones
@joneshf
Jan 10 2017 10:15
Sure.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:15
because I tried really really hard and couldn't come up with much. maybe i'm blocked
there is a constraint where i can only place a transmitter on a house
Hardy Jones
@joneshf
Jan 10 2017 10:16
First thing, are all these methods pure?
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:16
this is the problem in case you need more context: https://www.hackerrank.com/challenges/hackerland-radio-transmitters
I'm not looking for answers
I've already solved it
Hardy Jones
@joneshf
Jan 10 2017 10:16
like GetNextTransmitterIndex and GetNextNonCoveredHouseIndex.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:17
private static int GetNextTransmitterIndex(IReadOnlyList<int> houseLocations, int current,
            int coverageLength)
        {
            var i = current;
            var location = houseLocations[current];
            while (i < houseLocations.Count - 1 && houseLocations[i+1] <= location + coverageLength)
            {
                i++;
            }
            return i;
        }

        private static int GetNextNonCoveredHouseIndex(IReadOnlyList<int> houseLocations, int transmitterIndex,
            int coverageLength)
        {
            var i = transmitterIndex;
            var location = houseLocations[transmitterIndex];
            while (i < houseLocations.Count - 1 && houseLocations[i + 1] <= location + coverageLength)
            {
                i++;
            }
            return ++i;
        }
yes they are
Hardy Jones
@joneshf
Jan 10 2017 10:17
Cool!
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:17
but i hate the while loops
Hardy Jones
@joneshf
Jan 10 2017 10:17
So that's the first step.
Ensure what you're calling is also pure.
At least for me.
Mostly because if I don't ensure the things I depend on are pure, it generally ends up biting me later on.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:18
yeah, I can follow that. I tried to make sure of it first as well
so there is no state etc. even though this is in c# i've tried to use pure functions
Hardy Jones
@joneshf
Jan 10 2017 10:18
great!
So you want to get rid of the loops.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:19
i have loops in all the three functions right? i want to get rid of all of them, if possible, under the realms of declarative FP
Hardy Jones
@joneshf
Jan 10 2017 10:20
Yep
Every loop can be replaced with some form of map, reduce or another function.
That other function being the more general version (though it's harder to understand so I'm not going to explain it right now).
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:21
i find it difficult to understand, especially with a problem of this kind
Hardy Jones
@joneshf
Jan 10 2017 10:21
Oh sure.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:21
it would be very educational and valuable to me
Hardy Jones
@joneshf
Jan 10 2017 10:21
So the thing to figure out is, what is it that you're iterating over.
Let's take a simple loop initially.
in GetNextTransmitterIndex you are doing a couple of checks in your while condition.
The first is i < houseLocations.Count - 1.
This condition is ensuring we stay within the bounds of the IReadOnlyList<int>
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:25
i can reach bounds + 1
Hardy Jones
@joneshf
Jan 10 2017 10:25
But that comes for free with map or reduce.
Hmm?
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:25
sorry
please proceed
Hardy Jones
@joneshf
Jan 10 2017 10:26
No, please. I might have misunderstood that condition.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:26
no no i took the other function. you are on the right track.
sorry for breaking your line of thought there
please go ahead
Hardy Jones
@joneshf
Jan 10 2017 10:26
No worries.
Oh...actually, looking at this, these are kind of complex examples to start with. :)
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:28
i could actually roll my own with lesser examples, or so I feel :(
maybe that's overestimating myself
Hardy Jones
@joneshf
Jan 10 2017 10:28
roll your own what?
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:28
roll my own declarative fp solutions, I meant
Hardy Jones
@joneshf
Jan 10 2017 10:29
Ah.
Maybe that's a better place to start then?
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:29
what do you suggest?
Hardy Jones
@joneshf
Jan 10 2017 10:30
What if we start breaking apart the functions you have.
Like, say we get rid of current as an argument, and always assume it's 0.
private static int GetNextTransmitterIndex(IReadOnlyList<int> houseLocations, int coverageLength)
{
    var current = 0;
    var i = current;
    var location = houseLocations[current];
    while (i < houseLocations.Count - 1 && houseLocations[i+1] <= location + coverageLength)
    {
        i++;
    }
    return i;
}
Do you think you could convert that?
Or should we go further?
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:32
const location = houseLocations[current];
const transmitterLocation =
  houseLocations
    .map((v, i) => {i, v}})
    .filter(x => x.i >= current)
    .filter(x => x.v <=  location + coverageLength)
    .pop().i;
Galileo Sanchez
@galileopy
Jan 10 2017 10:33
I would just use the first function, and the second will call the first and increment by one :)
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:33
sorry
give me a moment
Hardy Jones
@joneshf
Jan 10 2017 10:34
@artfuldev oh snap! that's pretty good!
Galileo Sanchez
@galileopy
Jan 10 2017 10:34
Oh no, excuse me for interrumpting, mind if I join @artfuldev @joneshf ?
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:34
const location = houseLocations[current];
const transmitterLocation =
  houseLocations
    .map((v, i) => {i, v}})
    .filter(x => x.i >= current)
    .filter(x => x.v <=  location + coverageLength)
    .pop().i;
this should be it
if i am not wrong
Hardy Jones
@joneshf
Jan 10 2017 10:35
I think you're right.
@galileopy I don't mind.
@galileopy and yeah, they're basically the same function.
Galileo Sanchez
@galileopy
Jan 10 2017 10:35
In this scenario, do you need iteration at all?
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:35
@galileopy please pitch in with what you think can be done
although I am trying to understand how to do away with the while loop in my first function
in which the iterator current changes value too much
Hardy Jones
@joneshf
Jan 10 2017 10:36
@galileopy I think you still do because you want to check all the values within the IReadOnlyList<int>.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:37
@galileopy if you do have time, can i finish trying to see what @joneshf is trying to explain to me? we can then together think about how to improve the existing implementation.
Galileo Sanchez
@galileopy
Jan 10 2017 10:37
yes, sorry, I missed that [i+1] in the condition
Hardy Jones
@joneshf
Jan 10 2017 10:37
@artfuldev so yeah, that totally works for GetNextTransmitterIndex and GetNextNonCoveredHouseIndex.
Galileo Sanchez
@galileopy
Jan 10 2017 10:37
go ahead.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:37
@joneshf can we proceed?
Hardy Jones
@joneshf
Jan 10 2017 10:38
Yep
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:38
nextUncoveredHouseIndex != nextTransmitterIndex + 1
that's the point
because, say coverage length is 7, i can have houses at 1, 7, 8,9,10,11,14,22
if i place a transmitter at index 1, at 7, then my next non-covered house is at 22, index 7
the transmitter on 7 covers houses from 1 to 14, say
@joneshf am I making any sense?
Hardy Jones
@joneshf
Jan 10 2017 10:40
Yeah, I think @galileopy's point was that the algorithm of those two methods is essentially the same, except you add 1 to GetNextNonCoveredHouseIndex. So, you could use one function for the algorithm, and just add 1 when you wanted to use the result of GetNextNonCoveredHouseIndex.
Galileo Sanchez
@galileopy
Jan 10 2017 10:41
@joneshf that's right
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:41
@galileopy @joneshf that is correct, yes
I was able to see it, just not see how it can be reused in a way that doesn't have state
Hardy Jones
@joneshf
Jan 10 2017 10:41
Like this or so:
private static int GetNextTransmitterIndex(IReadOnlyList<int> houseLocations, int current,
    int coverageLength)
{
    return UnderlyingAlgorithm(houseLocations, current, coverageLength);
}

private static int GetNextNonCoveredHouseIndex(IReadOnlyList<int> houseLocations, int transmitterIndex,
    int coverageLength)
{
    return UnderlyingAlgorithm(houseLocations, current, coverageLength) + 1;
}
Anyway!
So, I feel like we could solve it for GetNumberOfTransmitters, but that probably wouldn't help you much in the long run.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:43
oh?
but that's pretty hard for me as it stands
Hardy Jones
@joneshf
Jan 10 2017 10:43
Like, we can find a solution to a specific problem, but it sounds like you're more hung up on having a general solution.
Something that you can use the next time you want to make the conversion.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:43
yes
sorry if it's irksome
Hardy Jones
@joneshf
Jan 10 2017 10:43
Nope, not irksome at all.
I just don't want to waste your time. :)
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:44
there is no time wasted
do not worry
I was worried about your time, actually
Hardy Jones
@joneshf
Jan 10 2017 10:44
There is a really good read on this sort of thing by Fowler. Let me try to find the link.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:45
i have another problem - and that is single iteration.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:45
when i use this while and everything i get a single iteration
over the list of house locations
Hardy Jones
@joneshf
Jan 10 2017 10:45
It's a long read, but totally worth it.
I feel like it describes exactly what you're trying to solve.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:46
let me go through it
Hardy Jones
@joneshf
Jan 10 2017 10:46
You don't have to do it right now.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:46
do let me find you again, @joneshf
ok, that's even cooler
Hardy Jones
@joneshf
Jan 10 2017 10:46
I mean, you can if you'd like. But you don't have to.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:46
i would first learn about this specific case first
I have one problem with my own refactoring
can I proceed with that first?
Hardy Jones
@joneshf
Jan 10 2017 10:47
Sure.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:47
and then we can go back to the first loop
so yeah
const location = houseLocations[current];
const transmitterLocation =
  houseLocations
    .map((v, i) => {i, v}})
    .filter(x => x.i >= current)
    .filter(x => x.v <=  location + coverageLength)
    .pop().i;
this is what I refactored the getNextTransmitterIndex into
function getNextTransmitterIndex(houseLocations: number[], current: number, coverageLength: number): number {
  const location = houseLocations[current];
  const transmitterLocation =
    houseLocations
      .map((v, i) => {i, v}})
      .filter(x => x.i >= current)
      .filter(x => x.v <=  location + coverageLength)
      .pop().i;
}
right?
Hardy Jones
@joneshf
Jan 10 2017 10:49
Sure.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:49
so, if I called this multiple times
with the same houseLocations
Hardy Jones
@joneshf
Jan 10 2017 10:49
Oh, I see.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:49
same coverageLength but different current
I get multiple iterations over houseLocations
Hardy Jones
@joneshf
Jan 10 2017 10:50
Wait, I don't see. :)
Okay.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:50
is that a problem, or am i missing the .filter((v, i) => ) signature?
Hardy Jones
@joneshf
Jan 10 2017 10:51
I don't understand the question.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:51
I'm really bad at this I guess
gimme a min
You can see these two lines, right?
Hardy Jones
@joneshf
Jan 10 2017 10:52
It's not all you. It's 3AM for me :wink:.
Galileo Sanchez
@galileopy
Jan 10 2017 10:52
you want to iterate only from current and not from the beggining?
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:52
.map((v, i) => {i, v}})
and
.pop().i;
@galileopy yep, one part
I also want to hold onto the original i, and not the new i after the first filter
Galileo Sanchez
@galileopy
Jan 10 2017 10:53
you can slice and zip with range(current, end)
so you do not need to map to add the index
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:54
@galileopy I guess if I'm to understand, you need to lay it all out at a more basic level. I'm finding it hard to follow
I just had a thought. I don't need the original i at all. I can just get the i from the filter function's result, and then return current + i
Hardy Jones
@joneshf
Jan 10 2017 10:55
@artfuldev I see the two lines, yeah.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:56
function getNextTransmitterIndex(houseLocations: number[], current: number, coverageLength: number): number {
  const location = houseLocations[current];
  const transmitterLocation =
    houseLocations
      .filter((x,i) => i >= current)
      .filter(x => x <=  location + coverageLength)
      .length;
  return transmitterlocation + current - 1;
}
This is without holding on to the i and so a map operation was unnecessary, I guess
or I am rushing without seeing if it is right
Hardy Jones
@joneshf
Jan 10 2017 10:58
@artfuldev If we can take a step back. I feel like you have at least two different concerns here: one is the removal of while and the other is limiting the number of iterations.
Sudarsan Balaji
@artfuldev
Jan 10 2017 10:59
@joneshf yeah. but first we can go over either
@joneshf @galileopy single iteration, because for very large inputs I have a time constraint, and anything more than a single iteration doesn't cut it
Hardy Jones
@joneshf
Jan 10 2017 10:59
You should recognize that while you're learning how to convert from loops, you're going to end up with code that is less efficient.
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:00
oh... okay :(
valid point that I hadn't really given much thought about
Hardy Jones
@joneshf
Jan 10 2017 11:00
Trying to push hard for converting from loops and being as efficient or more efficient will necessarily make this process harder to learn.
You definitely can do what you're asking.
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:01
okay
first to converting my loops then
that will at least get closer to declarative FP
I'm happy with my last refactoring, if that's okay
Hardy Jones
@joneshf
Jan 10 2017 11:02
Yeah, that seems like the easier way to go. Once you feel comfortable, it's easier to make efficiency changes.
Sure.
The thing I really want to get across is that you have to know what you're iterating over in order to remove the loop.
It's not always the index.
Galileo Sanchez
@galileopy
Jan 10 2017 11:04
ok, R.range generates a list form number A to B, and R.zip joins to lists together so if you have [3,4,57,88] and you want [[57,2],[88, 3]], you first generate [57,88] then [2,3] and you R.zip them, to get [[57,2],[88, 3]] then you filter over it, take the first and get it's 2nd value
const fromCurrent = R.slice(current, houseLocations.length, houseLocations);
const indexes = R.range(current, houseLocations.length);
const indexedList = R.zip(fromCurrent, indexes);
const pairs =  indexedList.filter(x => x[0] <=  location + coverageLength);
return pairs[0][1]
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:05
@galileopy got it now, thanks :)
@joneshf so like @galileopy I only needed one function. so I have refactored both my functions to
function getNextTransmitterIndex(houseLocations: number[], current: number, coverageLength: number): number {
  return getNextUncoveredLocationIndex(houseLocations, current, coverageLength) - 1;
}

function getNextUncoveredLocationIndex(houseLocations: number[], current: number, coverageLength: number): number {
  const location = houseLocations[current];
  const transmitterLocation =
    houseLocations
      .filter((x,i) => i >= current)
      .filter(x => x <=  location + coverageLength)
      .length;
  return transmitterlocation + current;
}
Galileo Sanchez
@galileopy
Jan 10 2017 11:06
and if you want to optimize you can change filter to find
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:06
now these functions are pure, and declarative fp
Hardy Jones
@joneshf
Jan 10 2017 11:06
Cool!
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:07
how do I refactor the first function now?
private static int GetNumberOfTransmitters(IEnumerable<int> houseLocations, int coverageLength)
{
    var distinctSortedHouseLocations = houseLocations.OrderBy(x => x).Distinct().ToList();
    if (distinctSortedHouseLocations.Count == 1) return 1;
    var count = 0;
    var current = 0;
    while (current < distinctSortedHouseLocations.Count)
    {
        var transmitterIndex = getNextTransmitterIndex(distinctSortedHouseLocations, current, coverageLength);
        count++;
        current = getNextUncoveredLocationIndex(distinctSortedHouseLocations, transmitterIndex, coverageLength);
    }
    return count;
}
Hardy Jones
@joneshf
Jan 10 2017 11:07
You have to identify what you're iterating over.
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:08
i am iterating over...
locations of the houses?
i am trying to find the next uncovered location within the range, and then place a transmitter over that location.
then i will go to the next house that is not uncovered, and repeat step 1 again
Hardy Jones
@joneshf
Jan 10 2017 11:11
Sorry, I was having computer problems. My sentence was vague.
Umm, I think what you're iterating over is the state of current.
I don't really understand the algorithm enough to say how to go forward from here.
Galileo Sanchez
@galileopy
Jan 10 2017 11:13
i would start from R.compose(R.sort, R.uniq) and build up from there
meaning, that the first line is the only thing that I see how to refactor xD
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:13
can you please gimme 5 mins?
sorry about this
Hardy Jones
@joneshf
Jan 10 2017 11:14
@galileopy haha, at least i'm not the only one :)
@artfuldev take your time.
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:16
a sudden meeting came up
gimme 5-10
sorry
i'm the one who needs help, so
Hardy Jones
@joneshf
Jan 10 2017 11:17
No worries. I'll continue, but don't rush to respond.
Remember that I said any loop can be converted to map, reduce or another function. That's still true, but it might not end up looking nice depending on the loop you came from.
Galileo Sanchez
@galileopy
Jan 10 2017 11:17
Also I would split the loop in two then translate the other loop
Hardy Jones
@joneshf
Jan 10 2017 11:18
In this case, since there's current and it's being mutated, the conversion will have a good deal of machinery in order to replicate this mutation.
Galileo Sanchez
@galileopy
Jan 10 2017 11:19
the other thing I would do change var transmitterIndex to let transmitterIndex since var has function scope and let has block scope
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:19
that var is in C#
I've used const where possible in my latest javascript refactor
meeting just ended
Galileo Sanchez
@galileopy
Jan 10 2017 11:21
Also, I wouldn't start by trying to translate, generally a functional program is a completely different program than a procedural one, I might be mistaken though and that is just personal preference, I would start by defining the input/output of each function and work my way into bulding a functional function with the same in/out one step a a time
Hardy Jones
@joneshf
Jan 10 2017 11:22
I agree. That's actually a better way to proceed in this case.
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:22
function getNumberOfTransmitters(houseLocations: number[], coverageLength: number): number
{
    const distinctSortedHouseLocations = houseLocations.sort((a,b) => b - a).distinct();
    if (distinctSortedHouseLocations.length == 1) return 1;
    let count = 0;
    let current = 0;
    while (current < distinctSortedHouseLocations.length)
    {
        let transmitterIndex = getNextTransmitterIndex(distinctSortedHouseLocations, current, coverageLength);
        count++;
        current = getNextUncoveredLocationIndex(distinctSortedHouseLocations, transmitterIndex, coverageLength);
    }
    return count;
}
would be a close representation in JS
Galileo Sanchez
@galileopy
Jan 10 2017 11:23
the other thing I would do is use R.curry, to clean up the repeated params so you clearly see what is getting mutated and passed along
Hardy Jones
@joneshf
Jan 10 2017 11:23
Mostly because of the mutation that is both the loop condition and an input to a function in the body of the loop.
Actually, that's a good point! The reason I'm getting hung up here is because current is mutated, used as the loop condition and as the input to a function within the loop body. I think removing one of those three cases would make this thing easier.
For sure removing two would :).
It's also because I need sleep :).
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:25
I'm sorry if I'm asking too much, but can we, with what we know, try to construct a new solution which helps us solve this problem?
@joneshf sorry, please have a good night's sleep, thank you for taking me so far
Hardy Jones
@joneshf
Jan 10 2017 11:25
I hate to leave you hanging like this @artfuldev, but I'm going to have to sleep on this. Maybe someone else can help you in the meantime.
I'd go with @galileopy's suggestions.
Galileo Sanchez
@galileopy
Jan 10 2017 11:27
something like this
const nextTI = R.curry(getNextTransmitterIndex)(distinctSortedHouseLocations, R.__, coverageLength);
const nextUL = R.curry(getNextUncoveredLocationIndex)(distinctSortedHouseLocations, R.__, coverageLength)
    while (current < distinctSortedHouseLocations.length)
    {
        let transmitterIndex = nextTI(current);
        count++;
        current = nextUL(transmitterIndex);
    }
then it is clearer that you have function composition there current = nextUL(nextTI(current))
which you can translate to const getCurrent = R.compose(nextUL,nextTI)
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:29
another meeting, please gimme 5-10
Galileo Sanchez
@galileopy
Jan 10 2017 11:30
so you program could be
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:30
this is awesome, I can actually follow what's happening
Galileo Sanchez
@galileopy
Jan 10 2017 11:32
const nextTI = R.curry(getNextTransmitterIndex)(distinctSortedHouseLocations, R.__, coverageLength);
const nextUL = R.curry(getNextUncoveredLocationIndex)(distinctSortedHouseLocations, R.__, coverageLength);
const getCurrent =  R.compose(nextUL,nextTI);
while (current < distinctSortedHouseLocations.length)
{
    current = getCurrent(current); 
    count++;
}
then I would check if I can define getNextTransmitterIndex, getNextUncoveredLocationIndex with R.curry in the first place so you don't have to curry them before use
and I think you might be able to take it from here
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:39
is using while etc good declarative FP?
or is there some other way to achieve the same?
Galileo Sanchez
@galileopy
Jan 10 2017 11:39
I think we can reduce here, R.reduce(getCurrent, 0, distinctSortedHouseLocations) getCurrent will only use the acc and discard the value
that won't work
what do you want to do now?, get the first index that's greater than the length of your locations, right?
I'm not familiar with transducers, but for what I know that would be one way to accomplish that, if someone could show me the transducers way I would be grateful.
since you need a reduce that doesn't go all the way to the end, you'd better write your own function here
Galileo Sanchez
@galileopy
Jan 10 2017 11:49
var limit = distinctSortedHouseLocations.length;
 function inner  (current, count){
     if (current > limit) return invalidFlag;
     if (current === limit) return count;
     else {
         let next =  inner(getCurrent(current), count +1);
         return next === invalidFlag? current: next;
     }
}
Sudarsan Balaji
@artfuldev
Jan 10 2017 11:51
stuck in a meeting, struggling to get back
Galileo Sanchez
@galileopy
Jan 10 2017 11:52
that would be an inner function where the limit is closed over, however it does seem more complicated than it should be, I will probably just leave it the way it was with the while, since it is clearer
or
var limit = distinctSortedHouseLocations.length;
function inner  (current, count){
    if (current > limit) return count -1;
    if (current === limit) return count;
    else  return inner(getCurrent(current), count +1);
}
@artfuldev I assume you are familiar with recursion
@artfuldev I got to get back to work, I hope I helped :)
Gabe Johnson
@gabejohnson
Jan 10 2017 12:02
@hemanth I'm gonna need more context. Can you provide some code?
James Forbes
@JAForbes
Jan 10 2017 12:02
Maybe a function to define the increment/decrement separately to the recursion?
const comparator = (a,b) => 
      a > b 
         ? -1 
      : a < b 
         ? 1
      : 0
function inner(current, count){
  return comparator( current, count ) || inner( comparator(current, count) )
}
With some sneaky falseyness to lead us all astray
And maybe externalise the predicate for looping
Galileo Sanchez
@galileopy
Jan 10 2017 12:05
how do I refresh gitter?
it's hiding stuff
reload doesn't work
James Forbes
@JAForbes
Jan 10 2017 12:07
const predicate = ( current, count ) => current < limit

function inner(current, count){
  return (predicate( current, count ) ? inner: identity)( p, comparator (current, count) )
}
maybe we can define a recursive fn that accepts a predicate and a reducer?
function reduceUntil( predicate, reducer ){
  return function inner(p, n){
     var continuation = predicate(p,n) ? inner : identity
     return continuation( p, reducer( p,n) )
  }
}
reduceUntil( (a,b) => a < b, (a,b) => a > b ? -1 : a < b ? 1 : 0 )
Galileo Sanchez
@galileopy
Jan 10 2017 12:11
inner takes takes two args, I'm confused
James Forbes
@JAForbes
Jan 10 2017 12:11
But if I just saw that line I'd be like, "I have no idea what that does", so maybe naming the predicate and the comparator something might help
oh I missed getCurrent!
@galileopy what does getCurrent look like?
Galileo Sanchez
@galileopy
Jan 10 2017 12:12
Integer -> Integer
Denis Stoyanov
@xgrommx
Jan 10 2017 12:13
Galileo Sanchez
@galileopy
Jan 10 2017 12:13
@xgrommx that's exactly what it is needed
James Forbes
@JAForbes
Jan 10 2017 12:13
mmmm ramda
@xgrommx perfect
The usual pattern that happens for me is, separate transformation, from predicates, separate concerns and then when you see a pattern write a function for that pattern, then go to the ramda page and find they've already written it, and use that instead :D
it'd be more efficient to change the order, but that never works for me
Denis Stoyanov
@xgrommx
Jan 10 2017 12:17
but also smth like compose(reduce, takeWhile)
Galileo Sanchez
@galileopy
Jan 10 2017 12:19
@artfuldev it would end up like this
const getNextTransmitterIndex = R.curry(function () {});
const getNextUncoveredLocationIndex = R.curry(function () {});
const sortUnique = R.compose(R.sort, R.uniq);

function getNumberOfTransmitters(houseLocations: number[], coverageLength: number): number
{
    const houses = sortUnique(houseLocations);
    const nextTI = getNextTransmitterIndex (houses, R.__, coverageLength);
    const nextUL = getNextUncoveredLocationIndex(houses, R.__, coverageLength);
    const getCurrent =  R.compose(nextUL, nextTI);
    const reducer = R.evolve({
        current: getCurrent,
        count: R.inc
    });
    const cond = R.compose(R.lte(houses.length), R.prop('count'));
    return R.reduceWhile(cond, reducer, 0, houses).count;

}
ouch, insted of 0 it should be {current: 0, count : 0} for the starting argument in reduce
@xgrommx, I dont think compose(reduce, takeWhile) would work here, and neither would reduceWhile if the cond is applied to the argument before reduction
James Forbes
@JAForbes
Jan 10 2017 12:24
If reduceWhile works, I'd stop there, I personally think any further levels of abstraction would make it unclear, the above is easy to follow in my opinion
Galileo Sanchez
@galileopy
Jan 10 2017 12:24
I agree
James Forbes
@JAForbes
Jan 10 2017 12:24
its tempting to reorder the args of the getNext fns to avoid the placeholder
Denis Stoyanov
@xgrommx
Jan 10 2017 12:24
@galileopy why not?
Galileo Sanchez
@galileopy
Jan 10 2017 12:25
@JAForbes yes I want to reorder the args, @xgrommx because you need the last result of the reducer to check for the condition, with take while you have a value that is not being used
James Forbes
@JAForbes
Jan 10 2017 12:29
Total code golf now:
const cond = useWith( lte, [ length, R.prop('count') ]))
Galileo Sanchez
@galileopy
Jan 10 2017 12:30
xD nice
James Forbes
@JAForbes
Jan 10 2017 12:31

So you could technically move the function out of the closure but, its so coupled with the code theres not much point, what would you even name it?

listLengthLessThanCountProperty, so I'd keep it where it is, as it is, but its tempting to keep going sometimes

Galileo Sanchez
@galileopy
Jan 10 2017 12:31
@artfuldev you see that you have completely different program now?
Galileo Sanchez
@galileopy
Jan 10 2017 12:37
@JAForbes if eventually that reducer is needed somewhere else it could end up like
const getNextTransmitterIndex = R.curry(function () {});
const getNextUncoveredLocationIndex = R.curry(function () {});
const sortUnique = R.compose(R.sort, R.uniq);

function makeReducer(houses, coverageLength) {
    const nextTI = getNextTransmitterIndex (houses, R.__, coverageLength);
    const nextUL = getNextUncoveredLocationIndex(houses, R.__, coverageLength);
    return  R.evolve({
        current: R.compose(nextUL, nextTI),
        count: R.inc
    });
}

function getNumberOfTransmitters(houseLocations: number[], coverageLength: number): number
{
    const houses = sortUnique(houseLocations);
    const cond = R.useWith( R.lte, [ R.length, R.prop('count') ]));
    const reducer = makeReducer(houses, coverageLength);
    return R.reduceWhile(cond, reducer, 0, houses).count;
}
yes it is tempting to keep going, like defining the getNumberOfTransmitters = usewith(function (){}, [ sortUnique, identity])
cond could also go outside
and make reducer can be defined in terms of R.converge I think
Galileo Sanchez
@galileopy
Jan 10 2017 12:52
sorry, couln't help it
const getNextTransmitterIndex = R.curry(function () {});
const getNextUncoveredLocationIndex = R.curry(function () {});
const sortUnique = R.compose(R.sort, R.uniq);
const nexts = R.converge(R.compose, [getNextTransmitterIndex, getNextUncoveredLocationIndex]);
const makeReducer = (arr, len) => R.evolve({ current: nexts(arr, R.__, len), count: R.inc });
const cond = R.useWith( R.lte, [ R.length, R.prop('count') ]));
const count  = (houses, len) =>  R.reduceWhile(cond, makeReducer(houses, len), 0, houses);
const getNumberOfTransmitters = R.compose(
    R.prop('count'),
    R.useWith(count,  [sortUnique, R.identity])
);
Sudarsan Balaji
@artfuldev
Jan 10 2017 13:04
@galileopy no, I don't think it's a completely different program. It's evolved differently. :) As long I can see and follow the evolution, that's what I'd think. :D
thanks a lot
if I can get Ramdba out of it (look where I am) I will be able to take the concepts and use it elsewhere (outside of JavaScript) too :)
thank you, everyone, for helping with the evolution :)
Sudarsan Balaji
@artfuldev
Jan 10 2017 13:30
rambda seems to have several useful functions. do you think a c# port would be useful?
Sudarsan Balaji
@artfuldev
Jan 10 2017 13:36
sorry about the typos. 'ramda' it is. and excuse the port comment.
I'm just curious - do ramda functions support deferred execution?
Denis Stoyanov
@xgrommx
Jan 10 2017 13:38
@artfuldev c# has LINQ
James Forbes
@JAForbes
Jan 10 2017 13:42
completely academic, but technically with chakra core you could call code in JS, or call JS code from C#
I mean you could always do it before, but now its sort of worthwhile because its node's env not wsh, and its es6, and it supports node's api, and its not painfully slow
I think you can require dlls
Denis Stoyanov
@xgrommx
Jan 10 2017 13:45
Sudarsan Balaji
@artfuldev
Jan 10 2017 13:45
@xgrommx I am in love with LINQ but still, we lack several basic operators
Sudarsan Balaji
@artfuldev
Jan 10 2017 13:47
wow that's a nice list
cool
I mean the C# section, of course, the awesome list was already shared yesterday :)
Denis Stoyanov
@xgrommx
Jan 10 2017 13:47
Sudarsan Balaji
@artfuldev
Jan 10 2017 13:48
sadly several of those are abandoned
sorry, functional.NET in that list is abandonded
Sudarsan Balaji
@artfuldev
Jan 10 2017 14:02
nevertheless, awesome resources
James Forbes
@JAForbes
Jan 10 2017 14:04
I saw edge a long time ago but never tried it, looks really cool, and it seems there a PR to make it work with chakra as a backend which is great