These are chat archives for ramda/ramda

9th
Aug 2017
Dustin Stiles
@dustinws
Aug 09 2017 00:51

Since R.always is the basically just the K Combinator, does anyone else wish that it was instead named R.k or perhaps had an alias to R.K | R.k?
I tend to have a K sitting in my projects because I feel like it is easier to read than always, especially when there are multiple calls on the same line.

Am I alone in this, or are there other rebels out there?

Ian Hofmann-Hicks
@evilsoft
Aug 09 2017 01:39
@dustinws I would say it depends, a lot of time (IMO) always reads better in flow. But a lot of the time I usually just const K = require('ramda/src/always'). And to be honest, most of the time I bring in all my helpers into one util file called helpers. Sometimes, some libs do not work out of box with the current state of some other lib I am using. So if I need to change the api of some function like ap I can always exports.ap = flip(require('ramda/src/ap')). That way I only bring in functions in one place. also allows for testing on specific function in a lib that your code depends on. But anyway, you can always do exports.K = require('ramda/src/always') then if you switch libs, you can change it to the new lib exports.K = require('crocks/combinators/constant').
no point in having them make a MASSIVE breaking change, or a long winded deprecation cycle, for something as easy as mapping to your own preference.
Dustin Stiles
@dustinws
Aug 09 2017 02:18

@evilsoft Good points. I agree that always can read better depending on the situation, and I do use both. Though usually, I'll go with K.

Also, I do a similar thing with exporting functions from libs in a single file. I usually call it lang.js, and I'll use it to write my own implementation of some things as well.

I'm glad to hear that I'm not alone in this, though.

Dustin Stiles
@dustinws
Aug 09 2017 02:32

Also @evilsoft, I'm browsing through crocks. Pretty cool stuff. I did notice a type signature that looks weird, though I am still learning types.

For sequence you have this guy
Applicative f => (b -> f b) -> m (f a) -> f (m a)

But shouldn't it be this guy instead?
Applicative f => (a -> f a) -> m (f a) -> f (m a)

Like I said, I'm still learning, but I think the first version says that the return type of the first parameter is never used in the output, which isn't actually the case.

The project looks pretty sweet so far, I'm looking forward to playing around with it!

Gabe Johnson
@gabejohnson
Aug 09 2017 03:46
@dustinws sequence shouldn't take a function as an argument
traverse should though
Ian Hofmann-Hicks
@evilsoft
Aug 09 2017 03:47
that is the of for the fail case @gabejohnson
Gabe Johnson
@gabejohnson
Aug 09 2017 03:48
Guess I should look at the docs first :wink:
@evilsoft so these leading arguments handle exceptions?
Ian Hofmann-Hicks
@evilsoft
Aug 09 2017 04:08
@dustinws it is story time for mah boy, after that I will answer your bits . But I will probably do it in the crocks channel. Just to keep the noise down for such a silly lib in this room
Ian Hofmann-Hicks
@evilsoft
Aug 09 2017 04:14
But in the mean time, think of what would happen if I have an Either b [ a ] and then sequence on a Left. you would get a [ Either b a ].
I think maybe the return is faulty, but we can discuss that in the crocks channel. Will revisit though something is off there
Ian Hofmann-Hicks
@evilsoft
Aug 09 2017 04:52
@dustinws Okay, I answered your question to the best of my understanding in the crocks room.
Pasi Hirvonen
@pasih
Aug 09 2017 11:34
hm, I often want to update an item in a list based on a property. So [ { id: 1, foo: "bar" }, { id: 2, foo: "quux" } ] -> update id 2. I've used a few different ways to do but what do you guys think is the cleanest way? R.findIndex + R.adjust/R.update? I'm considering map() with R.when now.. (items.map(R.when(R.propEq("id", 1), ...))
Adam Szaraniec
@mimol91
Aug 09 2017 12:02
I think its better to have Map instead of array
You dont need to iterate for all of elements
Pasi Hirvonen
@pasih
Aug 09 2017 12:18
the data structure is not really in my control atm
I mean, yeah, I could convert back and forth but I kinda don't want to (for various reasons)
Adam Szaraniec
@mimol91
Aug 09 2017 12:35
I think I would use R.over
Kurt Milam
@kurtmilam
Aug 09 2017 14:38
Stuck on some recursion: https://goo.gl/T9h3Rc
// current result:
[[[["a", "b", "c", "d"]], ["a", "b", "e"]], [["a", "f", "g"]], ["a", "h"], ["a", "i"]]
// desired result:
[["a", "b", "c", "d"], ["a", "b", "e"], ["a", "f", "g"], ["a", "h"], ["a", "i"]]
Maybe I need to do something based on the current depth?
Jonah
@jonahx
Aug 09 2017 15:06
@kurtmilam will the first element always be the global root?
Kurt Milam
@kurtmilam
Aug 09 2017 15:08
yes
it's a rose tree
Denis Stoyanov
@xgrommx
Aug 09 2017 15:08
I don’t think so
Gabe Johnson
@gabejohnson
Aug 09 2017 15:09
And you want to output the party to each leaf node?
*path
Kurt Milam
@kurtmilam
Aug 09 2017 15:09
exactly. I want a flat list of all paths from root to leaves.
@xgrommx what don't you think?
Gabe Johnson
@gabejohnson
Aug 09 2017 15:11
@xgrommx it's a rose tree. Just encoded differently
Kurt Milam
@kurtmilam
Aug 09 2017 15:13
I'm perturbed that I'm stuck, because I've done this sort of thing plenty of times, but my brain is rebelling today.
Kurt Milam
@kurtmilam
Aug 09 2017 16:17
Got, I think: https://goo.gl/HUQJmb
The only questions:
  1. Could be done more elegantly?
  2. Is it a general solution, or will it break down given some as of yet untested configuration of input?
Kurt Milam
@kurtmilam
Aug 09 2017 16:36
Looks pretty resilient: https://goo.gl/sKqJbQ
That rose tree encoding is a pain to populate manually :D
Lihai Ben-Haim
@lihaibh
Aug 09 2017 16:38
does anyone have an opensource project that uses ramdajs?
i want to learn by looking on real life examples
because i dont understand when should i use ramdajs over traditional programming
Kurt Milam
@kurtmilam
Aug 09 2017 16:48
@lihaibh what do you mean by 'traditional programming'?
Michael Rosata
@mrosata
Aug 09 2017 16:49
@lihaibh this project is very small and uses Ramda https://github.com/mrosata/packt-mastering-fp/tree/volume-three - I don't personally have any real world projects that would be good to learn Ramda from. A good way to learn both Ramda and when to use and not to use Ramda functions over native ones would be to just use Ramda ones for awhile. You'll get better at the library, learning its different functions, and then you'll end up figuring out areas where you don't need ot use Ramda, where it could be overkill
when learning Ramda it can be easy to over use things, but it's also difficult to know where the right balance is. There is a lot to learn though, so I don't think over-use is such a bad thing at the start.
Lihai Ben-Haim
@lihaibh
Aug 09 2017 16:52
I got it but still it hard to think in Functional programming way, solving complex problems
because u dont think about the data you think about composing different logics together
in a functional way
unlike traditionaly when u invoke a function, have a new state of an object than u know what to do next
kind of thinking
Michael Rosata
@mrosata
Aug 09 2017 16:57
I guess that's a good metric then, if you take a problem and solve by using Ramda, differently than how you normally would w/o functional programming. Then you can ask yourself after,
a. is it pure
b. did I make the function more or less re-usable or readable,
c. is it too specific,
d. not specific enough?
The more you write the more you begin to think functionally. A lot of times people will ask questions in this channel. If your free at that time, try to solve the problem. Even if you don't post your result, you can wait until someone else does and then compare your solution to theirs
@lihaibh Try to figure out why they did something that you did differently. Many times it's because they saw something that they've seen many times before and their brain just clicked to that solution. Next time your solving a problem you may jump to a similar conclusion more quickly. You'll develop a mental model of where and how to start attacking problems.
Michael Rosata
@mrosata
Aug 09 2017 17:02
Lihai Ben-Haim
@lihaibh
Aug 09 2017 17:03
@mrosata thx i will look into it, anyway there is no negative impact if i just choose to use ramdajs over underscorejs right?
Michael Rosata
@mrosata
Aug 09 2017 17:04
I would say it's a step in the right direction if you're trying to get more serious about functional programming
there's only a couple things Ramda doesn't have that lodash has, like the delay function I think it's called, also chunk, but you can bring those in from lodash or write them yourself
Kurt Milam
@kurtmilam
Aug 09 2017 17:05
I'd definitely go with ramda over underscore or lodash, and I used to be a big fan of underscore, 7 or 8 years ago.
Lihai Ben-Haim
@lihaibh
Aug 09 2017 17:05
i see the potential but never faced it myself it sounds theoretical than practical
Michael Rosata
@mrosata
Aug 09 2017 17:05
@kurtmilam :+1:
Kurt Milam
@kurtmilam
Aug 09 2017 17:05
It's practical. Once you're in the mindset, you'll find that your code is often shorter, less complex and less buggy.
Lihai Ben-Haim
@lihaibh
Aug 09 2017 17:07
what about performance? is ramdajs has any major difference in performance compare to underscore?
Michael Rosata
@mrosata
Aug 09 2017 17:08
yea, I notice my code now adays still has problems naturally... but never really those "where the hell is that happening" or "what the heck is doing that" type problems I had before FP. I know where the issues are and just havent' solved them yet
Kurt Milam
@kurtmilam
Aug 09 2017 17:10
I'm not aware of any meaningful differences in performance.
Michael Rosata
@mrosata
Aug 09 2017 17:11
yea, I don't know about the performance difference in the two libraries, I don't think it's anything impactful
Kurt Milam
@kurtmilam
Aug 09 2017 17:11
There are lots of developers using Ramda, and I haven't heard any complaints about performance when using it.
Lihai Ben-Haim
@lihaibh
Aug 09 2017 17:13
theoretically javascript like any programming language has stack limits, when using functional programming it might cause performance issues (too many functional calls hierarchy) also potential overflow?
im coming from a c++ background so i think of those things lol
Kurt Milam
@kurtmilam
Aug 09 2017 17:14
Theoretically, although I've never had any issues with that.
Michael Rosata
@mrosata
Aug 09 2017 17:16
if you did run into a stack issue, it would probably be trying to solve a problem that would touch close to that limit regardless of Ramda or Lodash. I don't think Ramda has too many actual recursive functions in it anyways. I can't say 100%, but because of the way JavaScript handles recursion I think most the library is written with loops in places where a functional language would use recursion
Syaiful Bahri
@syaiful6
Aug 09 2017 17:27
@kurtmilam recurse it and build the paths by adding new labels from root to current node.
const listPathRoseTree = xs => {
  if (!Array.isArray(xs[1]) || isEmpty(xs[1])) return [[xs[0]]]
  return map(prepend(xs[0]), chain(listPathRoseTree, xs[1]))
}
Kurt Milam
@kurtmilam
Aug 09 2017 17:37
@syaiful6 thanks, that's much cleaner than mine :D
Kurt Milam
@kurtmilam
Aug 09 2017 18:01
I rearranged it a little to suit my style. Very clean solution. I should have paid more attention to determining whether each node was a leaf or not. Thanks again for the help @syaiful6 :)
REPL
const pathsFromTree = 
  tree => 
    !is( Array, tree[ 1 ] )
    || isEmpty( tree[ 1 ] )
      ? [ [ tree[ 0 ] ] ]
      : map( prepend( tree[ 0 ] ) )
           ( chain( pathsFromTree )
                  ( tree[ 1 ] )
           )
Jonathan Chang
@jdkschang
Aug 09 2017 18:33
holy shit it’s @xgrommx :O! I can’t tell you how invaluable the rx-book was for me. Couldn’t tell you how long I had that resource pinned in my browser as a guidepost for anything I tackled in rxjs. Thank you!
Denis Stoyanov
@xgrommx
Aug 09 2017 18:35
@jdkschang maybe later) I need come to home
Jonathan Chang
@jdkschang
Aug 09 2017 18:36
Back on topic :sweat_smile:, When writing ramda style code, do you write type signatures as you’re composing the building blocks as you go? at the end? or is it something you don’t even bother with?
Matthew Willhite
@miwillhite
Aug 09 2017 19:24
I like writing out the signature as practice, I like to think it helps me in composition as well…
of course as with most/all documentation it can get out of date pretty easily
Gabe Johnson
@gabejohnson
Aug 09 2017 19:28
:point_up:
Jonathan Chang
@jdkschang
Aug 09 2017 20:27
@miwillhite @gabejohnson thanks for the input! definitely going to write the signatures from now on. The question originated from my frustrations when I tried to combine functions without a base understanding why
André Bazaglia
@bazaglia
Aug 09 2017 20:38

Hello guys. I'm trying to write a rambda function that does the following:

  • Searches recursively inside an object for an attribute (example: reference: true) and then get its parent key and pushes to an array.

Example

properties: {
    name: {
      type: 'string',
      reference: true,
    },
    deep: {
      type: 'object',
      properties: {
         name: {
           type: 'string',
           reference: true,
         },
       }
    }
  }

should return ['name', 'deep.name']

Any suggestion of which rambda functions should I use? thank you.

Bijoy Thomas
@bijoythomas
Aug 09 2017 20:59
@bazaglia you can flatten you nested obj into '.' separated keys using this https://github.com/ramda/ramda/wiki/Cookbook#flatten-a-nested-object-into-dot-separated-key--value-pairs, and then find a key that matches your key to find
Denis Stoyanov
@xgrommx
Aug 09 2017 21:24
Jonathan Chang
@jdkschang
Aug 09 2017 21:51
@xgrommx thank you :smiley: The similar library link 404’s for me :P
Denis Stoyanov
@xgrommx
Aug 09 2017 22:02
@jdkschang try to use sidebar menu
Jonah
@jonahx
Aug 09 2017 22:15
@kurtmilam another working variation:
const isTree = x => is(String, x[0]) && x.length == 2

const flattenTree = t =>
  isTree(t)
    ? converge(map, [pipe(head, prepend), pipe(nth(1), chain(flattenTree)) ])(t)
    : t
interstingly, i tried to write a point-free version (which arguable isn’t an improvement anyway) but apparently when does not play nice with recursion, as this errors:
const flattenTree = when(
  isTree,
  converge(map, [pipe(head, prepend), pipe(nth(1), chain(flattenTree)) ])
)

error:

  converge(map, [pipe(head, prepend), pipe(nth(1), chain(flattenTree)) ])
                                                         ^

ReferenceError: flattenTree is not defined

oh but it is!

Dustin Stiles
@dustinws
Aug 09 2017 22:26

Not yet :)

flattenTree is still initializing because when hasn't finished evaluating.

Jonah
@jonahx
Aug 09 2017 22:28
@dustinws yeah i realised when actually executes converge (and hence its args) to create a curried function when it’s called.
whereas the ternary’s expressoin aren’t eval’d till its called
Bijoy Thomas
@bijoythomas
Aug 09 2017 22:35
hmm but then how does this work
  var foo = compose(
    inc,
    foo,
    inc
  )
compose will reverse the args for the pipe call
ah .. never mind .. foo(1) returns an error .. seems like foo is undefined :-)
Kurt Milam
@kurtmilam
Aug 09 2017 22:38
Point free recursive doesn't work. I learned that a few months ago :)
@jonahx thanks for the example!
Bijoy Thomas
@bijoythomas
Aug 09 2017 22:57
@kurtmilam that's an interesting observation!
Jonah
@jonahx
Aug 09 2017 23:15

consider an object whose values are transformation functions:

  transforms: {
    amount: key => amt => {
      key === 'D'
        ? Number(R.init(String(amt)) || 0)
        : Number(String(amt) + key)
    },
    focus: R.identity
  },

and now I want to map over these functions, to create decorated functions (the details of the decorator are irrelevant):

    const updates = {
      amount: key => updateWith(transforms.amount(key), 'amount', update),  // <— ISSUE ON THIS LINE
      focus: updateWith(transforms.focus, 'focus', update)
    }

the problem is, i can’t map over editAmount because it happens to be a function constructor, ie, you give it key and it returns the function we need to make updates. So in this case the decorator updateWith has to go to the right of key =>. but this messes up my hopes for just mapObjIndexeding updateWith over transforms and its keys to produce updates. is there anything that can be done here to avoid manually creating updates and retyping a bunch of boilerplate?

Kurt Milam
@kurtmilam
Aug 09 2017 23:28
@jonahx so you want to insert something between key and amt in the transforms object?
/ wrap the amt => function?
Jonah
@jonahx
Aug 09 2017 23:59
@kurtmilam so if there were no amt =>i could just write updates = mapObjIndexed((trans, name) => updateWith(trans, name, update), but key => screws that up. i can’t see a way push updateWith inside of key, as it were