These are chat archives for ramda/ramda

6th
Sep 2017
Chris Domigan
@cdomigan
Sep 06 2017 03:01
Am I right that R.call does not support placeholders?
const caller = R.call(R.__, "foobar");
caller(R.identity); // doesn't work
R.call(R.identity, "foobar"); //does work
Bijoy Thomas
@bijoythomas
Sep 06 2017 03:12
call(inc, __)(1) does work .. so maybe the placeholder is not supported on the function
but you can also do flip(call)(1)(inc) .. not sure if this will work in your case
flip(call)("foobar")(identity) seems to work :-)
Chris Domigan
@cdomigan
Sep 06 2017 04:09
@bijoythomas Thanks!
Isaac
@IsaacRaja_twitter
Sep 06 2017 04:14
state.search.filters.destination.map((destination) => {
  destination.partialTick = destination.countries.filter((country) => (country.checked));
  destination.partialSelected = destination.partialTick.length !== destination.countries.length;
});
I'm having difficulty refactoring the above
I know i could use lenses to modify the the destination.partialTick and destination.partisalSelected properties
how do I split these, pointfree. should I write a separate functions for the two statments inside and run R.over it?
Isaac
@IsaacRaja_twitter
Sep 06 2017 04:22
This looks straightforward by passing the arguments and mutating the original variable.
Kurt Milam
@kurtmilam
Sep 06 2017 09:22
@IsaacRaja_twitter You can make it easier on people who'd like to help you if you work up some examples with sample data in the REPL.
Julio Borja Barra
@juboba
Sep 06 2017 09:31

hey guys, I have this horrible imperative code I would like to refactor:

function getLocations(locations) {
  let result = []

  if (isObject(locations)) {
    const { countries = [], regions = [], cities = [] } = locations

    if (countries.length > 0) {
      result.push({ locationCountry: { $in: countries } })
    }

    if (regions.length > 0) {
      result.push({ locationRegion: { $in: regions } })
    }

    if (cities.length > 0) {
      result.push({ locationCity: { $in: cities } })
    }
  }

  return result
}

I created a function to check every prop const isFilled = propSatisfies(both(isArray, x => x.length > 0)) and I was going to use a pipe with whens, but I'm sure there must be a better way...

Kurt Milam
@kurtmilam
Sep 06 2017 10:42
@IsaacRaja_twitter I've started a refactor of your code from here in the REPL. Really, though, the original code is putting off a number of smells, in my opinion. I don't know the codebase, but I'm pretty sure there's a lot I'd change about this functionality (and probably a lot I'd change elsewhere in the codebase, judging by this and other code samples you've shared here recently). To be clear, I don't think it's a great idea to refactor smelly imperative code into smelly functional code.
Kurt Milam
@kurtmilam
Sep 06 2017 11:04
@IsaacRaja_twitter Here's an updated REPL with partialSelected being set correctly. As you can see, I went to the trouble of creating a minimal sample data set that seemed to match what you're working with.
Some smells:
  1. Three names are used for the same concept ('tick', 'checked', 'selected')
  2. Do we really need to store partialTick on the state?
  3. In most cases, I would avoid storing a derived value like partialSelected on the state, preferring, instead, to simply derive it when necessary. There are exceptions to this rule, but I'd guess they don't apply here.
Kurt Milam
@kurtmilam
Sep 06 2017 11:09
These issues make the functional solution more complex that it would otherwise need to be. Unless there were compelling reasons to do otherwise, I would probably write an allChecked function that would simply return true or false without updating the state at all.
Kurt Milam
@kurtmilam
Sep 06 2017 11:42
@juboba will countries, regions or cities ever be anything other than arrays?
I mean within locations, not after destructuring.
Also, what are the possible types of values in location.cities (prior to destructuring)? Always an array? Array with at least one entry, or else undefined?
Isaac
@IsaacRaja_twitter
Sep 06 2017 11:56
@kurtmilam Thanks, for the refactor and pointing the code smells. It's an old code, which i'm trying to refactor one at a time as I'm learning fp in js. I can't refactor them as a whole since I don't know much about the code base or fp in js. I'll also try to include some sample data with the code examples. Thanks again for the help.
Kurt Milam
@kurtmilam
Sep 06 2017 12:01
@IsaacRaja_twitter I totally understand. Unfortunately, I think it can be counterproductive to try to refactor smelly imperative code into smelly functional code. Better is to try to remove the smells and then refactor to clean functional code. Otherwise, you may end up (as in this case) with complex functional solutions that do a lot of unnecessary things. The resulting code can be difficult to read and refactor down the road, as you get a better handle on the codebase.
In this case, I would try to identify every place in the codebase that uses partialTick and partialSelected. If partialTick is only used to set partialSelected, I wouldn't set partialTick on the state.
Same for partialSelected. If it's not referenced all over the codebase, I'd try to turn it into a function that just returns true or false based on the current state. Then you just pass state into the function wherever you need to know whether partialSelected is true or not.
If you can avoid having to set these two values on state, you'll get rid of some smells, and the functional solution will become simpler.
Kurt Milam
@kurtmilam
Sep 06 2017 12:12
And moving to more advanced topics, an atom (a type of observable similar in some ways to a stream) would probably be a great place to store the current derived partialSelected value.
Julio Borja Barra
@juboba
Sep 06 2017 12:34
@kurtmilam yes, they are arrays of 'DE', 'CA', etc for countries, and other predefined strings for the regions and cities. And yes, they are always Arrays or undefined.
Kurt Milam
@kurtmilam
Sep 06 2017 12:35
OK, so if there are no cities, locations won't have a cities property, correct?
iow, when there are no cities, R.hasIn( 'cities', locations ) //-> false.
Julio Borja Barra
@juboba
Sep 06 2017 13:03
that's right
Kurt Milam
@kurtmilam
Sep 06 2017 13:12
@juboba are the keys in locations set in stone? Could we change locations.cities to locations.locationCity or locations.city, for instance?
Part of what this code is doing is renaming these keys, and the code could be simplified if we could do away with that step.
A key like locationCity could be used as-is. A key like city could be used with minor manipulation (upper case the first letter, then prepend 'location').
It's not easy to go from a key like 'cities' to one like 'locationCity' in a declarative, reusable manner, however. It will practically have to be imperative.
Kurt Milam
@kurtmilam
Sep 06 2017 13:30
@juboba Here's an example showing how simple the solution would be if we could control the key names in locations:
const data =
  { locationCountry: [ 'AT', 'US' ]
  , locationRegion: [ 'Carinthia', 'Texas' ]
  }

const getLocations =
  o( reduce( ( acc, x ) =>
               append( { [ head( x ) ]: { $in: last( x ) } } )
                     ( acc ) 
           )
           ( [] )
   )
   ( toPairs )
getLocations( data )
//-> [{"locationCountry": {"$in": ["AT", "US"]}}
//   ,{"locationRegion": {"$in": ["Carinthia", "Texas"]}}
//   ]
Julio Borja Barra
@juboba
Sep 06 2017 13:38
@kurtmilam yes, they are fixed parameters
wow, interesting code dude, thanks!
I'll read it carefully
Kurt Milam
@kurtmilam
Sep 06 2017 13:39
That's too bad, as it adds unnecessary complexity to the solution. Are the 'locationCountry' and 'locationRegion' keys also set in stone?
If they're also set in stone, I can work up a solution that takes care of the necessary renaming.
Isaac
@IsaacRaja_twitter
Sep 06 2017 13:43
@kurtmilam Any pointers on thinking in functional programming style?
Hi Guys, Is there any opensource project / code written using ramda that I can read?
Julio Borja Barra
@juboba
Sep 06 2017 13:46
@kurtmilam the words 'country', 'region' and 'city' are fixed so you don't need to worry about them
I thought that would make things easier
I didn't know o
ohh, now I see what you say
Kurt Milam
@kurtmilam
Sep 06 2017 13:59
@juboba names like 'countryList', 'cityList' would also be easier to convert than 'countries' and 'cities'.
@IsaacRaja_twitter well, refactoring complex imperative code may be a complicated way to get started with functional programming. Easier would probably be to find smaller, self-contained units of imperative code that you can safely convert completely.
Your last example may or may not be self-contained, depending on how the side effects it generates are used throughout the rest of the code base.
If you can verify that it's self-contained or can determine that the side effects aren't used in too many places, you could probably safely refactor that code from imperative with smells to function without smells :)
Isaac
@IsaacRaja_twitter
Sep 06 2017 14:24
ok, :)
Barry G
@bgits
Sep 06 2017 14:34
How can I use a nested filter like here where the last object should be returned? http://bit.ly/2vc1yvi
Kurt Milam
@kurtmilam
Sep 06 2017 14:35
your link goes to a google map search for 'golf course' :)
Barry G
@bgits
Sep 06 2017 14:35
woops, try this: http://bit.ly/2wI8WQz
sorry about that
Kurt Milam
@kurtmilam
Sep 06 2017 14:46
@bgits this works if all of the objects in the list contain z:{ y:[] }
const data = [
    {username: 'bob', age: 30, tags: ['work', 'boring'], z:{y:[]}},
    {username: 'jim', age: 25, tags: ['home', 'fun'], z:{y:[]}},
    {username: 'jane', age: 30, tags: ['vacation', 'fun'], z:{y:['fun']}}
]
R.filter( R.pipe( R.path( [ 'z', 'y' ] ) 
                , R.contains( 'fun' )
                )
        )
        (data)
Kurt Milam
@kurtmilam
Sep 06 2017 15:00
Your REPL link specified an older, pre o version of Ramda. If you're using the latest version of Ramda, I'd replace R.pipe with R.o, as I've done here.
Barry G
@bgits
Sep 06 2017 15:01
o is like compose?
Kurt Milam
@kurtmilam
Sep 06 2017 15:01
yes, o is like compose with exactly two functions.
That's how compose usually works in functional languages.
Ramda's compose is similar to (but not exactly) a right-to-left version of how pipe works in most functional languages.
So R.o is truer to the real compose than R.compose is.
Kurt Milam
@kurtmilam
Sep 06 2017 15:07
I wouldn't be surprised if R.compose was deprecated and/or became an alias of R.o some time in the distant future. And I expect R.pipe will someday be changed from a variadic function to a binary function, as well.
Isaac
@IsaacRaja_twitter
Sep 06 2017 15:09
@kurtmilam your comments are interesting. Off topic: Which functional language I can start learning?
Kurt Milam
@kurtmilam
Sep 06 2017 15:10
@IsaacRaja_twitter Haskell, OCaml, F#, Clojure would probably all be good candidates.
I haven't learned any of those yet, but I'd probably start with Haskell.
Isaac
@IsaacRaja_twitter
Sep 06 2017 15:11
oh, then which one you learned?
Kurt Milam
@kurtmilam
Sep 06 2017 15:11
I think Ramda is a pretty good introduction to functional programming if you're familiar with and already working with JavaScript.
I haven't learned any of those languages yet :) The only nominally functional language I've worked with significantly is XSLT.
Isaac
@IsaacRaja_twitter
Sep 06 2017 15:12
Thanks!
Kurt Milam
@kurtmilam
Sep 06 2017 15:12
I have played with and read a good deal about Haskell and Erlang, but haven't used them in real projects yet.
Matthew Willhite
@miwillhite
Sep 06 2017 15:29
@IsaacRaja_twitter Just going through some basic Haskell readings will give you enormous insights into what libs like Ramda and Sanctuary are doing
Isaac
@IsaacRaja_twitter
Sep 06 2017 15:35
@miwillhite sure, Thanks
Brad Compton (he/him)
@Bradcomp
Sep 06 2017 15:57

yes, o is like compose with exactly two functions.

The other difference with o is that it is curried, and the resultant function accepts exactly one argument. These differences can allow for certain things that aren't possible with compose.

EmilLindfors
@EmilLindfors
Sep 06 2017 19:12

hey guys, just a quick question regarding object composition when working with ramda.
I'm using React and have a prop looking like this: `

arrOne : [
        {arrOneIndex : 1, arrTwo: [{first : 98},{second : 2},{third : 10},{fourth : 0},{fifth : 1}]},
        {arrOneIndex : 2, arrTwo: [{first : 98},{second : 7},{third : 0},{fourth : 0},{fifth : 1}]},
        {arrOneIndex : 3, arrTwo: [{first : 1},{second : 23},{third : 8},{fourth : 0},{fifth : 1}]},
    ],

Is that a good way to structure things to be able to do ramda magic easily or is there a more efficient structure?

Bijoy Thomas
@bijoythomas
Sep 06 2017 19:16
@EmilLindfors any reason why you cannot use vanilla array indexes instead of labeling the values with a key that denotes an index?
EmilLindfors
@EmilLindfors
Sep 06 2017 19:18
I should probably have mentioned that the indexes are names and are displayed in the component. And that the user can supply whatever array and name they want as props - so these are just the default props. Sorry!
Bijoy Thomas
@bijoythomas
Sep 06 2017 19:27
ah ok .. your solution prob depends on how you want to use this data structure .. perhaps putting together something in the REPL might help
EmilLindfors
@EmilLindfors
Sep 06 2017 19:33
I added the accessors I use. They can pobably be improved - but they show what I need to do at least: https://goo.gl/d3nRBC
Vince Speelman
@VinSpee
Sep 06 2017 19:50

Hi! I'm refactoring a library and trying to do it "the ramda way", but having some trouble solving things idiomatically.

I have a map that looks like this:

const propsMap = {
  c: {
    property: 'cursor',
    value: [
      ['h', 'help'],
      ['n-a', 'not-allowed'],
      ['g', 'grab'],
      ['gg', 'grabbing'],
      ['p', 'pointer'],
      ['d', 'default'],
      ['a', 'auto'],
      ['n', 'none'],
      ['init', 'initial'],
    ],
  },
};

it has a variety of keys. I want to write a function that takes an object looking like this:

const data = {
  c:  'h',
};

and returns this:

{
  cursor: 'help'
}
I have complete control of the propsMap data structure, so I can adjust it as need be. Any pointers on heading in this direction?
here's my feeble attempt so far: https://goo.gl/PYTE7k
Vince Speelman
@VinSpee
Sep 06 2017 20:02
on a more theoretical level, I'm wondering how to effectively work with two different sets of data, an "input" and some sort of ruleset
Bijoy Thomas
@bijoythomas
Sep 06 2017 20:08
@EmilLindfors have you considered using a Maybe type to account for any null/undefined returns from your find
EmilLindfors
@EmilLindfors
Sep 06 2017 20:17
@bijoythomas I havent considered that - guess I should explore that option, thanks!
Bijoy Thomas
@bijoythomas
Sep 06 2017 21:06
@EmilLindfors :thumbsup:
Kurt Milam
@kurtmilam
Sep 06 2017 23:07
@VinSpee This works (REPL), although it's not point free, and I'm not sure whether it meets all of your requirements:
const getName =
  pMap =>
    o( pipe( path( [ 'c', 'value' ] ) 
           , fromPairs
           , flip( prop )
           )
           ( pMap )
     )
     ( prop( 'c' ) )

getName( propsMap )
       ( data ) //-> 'help'
Kurt Milam
@kurtmilam
Sep 06 2017 23:15
I'm not sure whether it's safe to hard code 'c' here. You could make this point free, but I'd probably stick with the pointful version.
Kurt Milam
@kurtmilam
Sep 06 2017 23:25
I overlooked that you wanted {cursor: "help"} instead of just "help". This REPL gives the correct return value.