These are chat archives for ramda/ramda

15th
Aug 2016
Martin Broder
@mrtnbroder
Aug 15 2016 08:39
is there something like flattenObj in ramda?
Kurt Milam
@kurtmilam
Aug 15 2016 09:11
Any good, functional patterns for branching based on an argument's type?
const f = function(x) {
  if (R.is(Object, x)) {
    // do Object stuff
  } else if (R.is(Number, x) {
    // do Number stuff
  }
}
Scott Christopher
@scott-christopher
Aug 15 2016 09:29
@kurtmilam R.cond can be helpful for describing switch/case style functions.
@ram-bot
const f = cond([
  [is(Object), keys],
  [is(Number), add(10)]
])
f(10)
ram-bot
@ram-bot
Aug 15 2016 09:31
undefined
Scott Christopher
@scott-christopher
Aug 15 2016 09:31
hmm... don't know why @ram-bot doesn't like that
but you get the gist
@ram-bot
const fn = cond([
  [is(Object), keys],
  [is(Number), add(10)]
])

fn({a: true})
ram-bot
@ram-bot
Aug 15 2016 09:32
[ 'a' ]
Scott Christopher
@scott-christopher
Aug 15 2016 09:33
R.cond
Scott Christopher
@scott-christopher
Aug 15 2016 09:33
@mrtnbroder Do you have an example of the expected input/output for flattenObj?
Kurt Milam
@kurtmilam
Aug 15 2016 09:34
@scott-christopher Thanks - I will mull that over a bit.
Scott Christopher
@scott-christopher
Aug 15 2016 09:37
Sure. R.cond basically takes an array of 2-element arrays which contain a predicate function in the first position (the "if" check) and a result function in the second position (the "then" part)
Kurt Milam
@kurtmilam
Aug 15 2016 09:37
re: flattenObj, this is the input and output of a flattenObj fn I've written:
const obj = {a:1, b:{c:3}, d:{e:{f:6}}}
const flatPOJO = flattenPOJO(obj)
/* flatPOJO = 
{
  a: 1
  , ['b.c']: 3
  , ['d.e.f']: 6
}
*/
Scott Christopher
@scott-christopher
Aug 15 2016 09:38
This creates a new function that when given some value will try each predicate until one returns true and then return the result of applying the function in the second position to the same value
Kurt Milam
@kurtmilam
Aug 15 2016 09:41
but my flattenObj (called flattenPOJO) needs to be refactored, Ramda-style
@scott-christopher That looks much cleaner than what I'm currently doing. Thanks for the example and explanation.
Scott Christopher
@scott-christopher
Aug 15 2016 10:26
@kurtmilam I'm sure there is a more elegant solution than this brute-force attempt, but it seems to do the trick:
This message was deleted
ram-bot
@ram-bot
Aug 15 2016 10:26
Unexpected token [
Scott Christopher
@scott-christopher
Aug 15 2016 10:27
I don't think @ram-bot likes destructuring arguments
@ram-bot
const flattenPOJO = obj => {
  const isObj = x =>
    typeof x == 'object' && x != null && x.constructor !== Array

  const joinPrefix = (prefix, k) =>
    prefix.length > 0 ? `${prefix}.${k}` : k

  const mapDeep = (prefix, obj) =>
    map((pair) => {
      const k = pair[0],
            v = pair[1]
      if (isObj(v)) {
        return unnest(mapDeep(joinPrefix(prefix, k), v))
      } else {
        return [joinPrefix(prefix, k), v]
      }
    }, toPairs(obj))

  return fromPairs(mapDeep('', obj))
}

flattenPOJO({a:1, b:{c:3}, d:{e:{f:6}}})
ram-bot
@ram-bot
Aug 15 2016 10:27
{ a: 1, 'b.c': 3, 'd.e.f': 6 }
Scott Christopher
@scott-christopher
Aug 15 2016 10:44
Managed to get it a bit more succinct:
@ram-bot
const isObj = x =>
    typeof x == 'object' && x != null && x.constructor !== Array

const flattenObj_ = pipe(toPairs, chain((pair) =>
  isObj(pair[1]) ? map((x) => [pair[0]+'.'+x[0], x[1]], flattenObj_(pair[1])) : [[pair[0], pair[1]]]))

const flattenObj = pipe(flattenObj_, fromPairs)

flattenObj({a:1, b:{c:3}, d:{e:{f:6}}})
ram-bot
@ram-bot
Aug 15 2016 10:44
{ a: 1, 'b.c': 3, 'd.e.f': 6 }
Kurt Milam
@kurtmilam
Aug 15 2016 10:51
@scott-christopher Looks good! My function also works on arrays (which I didn't mention previously):
const input = {a:1, b:{c:3}, d:{e:{f:6}, g:[{h:8, i:9}, 0]}}
//output:
{ a: 1, 'b.c': 3, 'd.e.f': 6 , 'g.0.h': 8, 'g.0.i': 9, 'g.1': 0}
Scott Christopher
@scott-christopher
Aug 15 2016 11:07
I think you could get away with removing the check in isObj to avoid Arrays.
@ram-bot
const flattenObj_ = pipe(toPairs, chain((pair) =>
  typeof pair[1] == 'object' ? map((x) => [pair[0]+'.'+x[0], x[1]], flattenObj_(pair[1])) : [pair]))

const flattenObj = pipe(flattenObj_, fromPairs)

flattenObj({a:1, b:{c:3}, d:{e:{f:6}, g:[{h:8, i:9}, 0]}})
ram-bot
@ram-bot
Aug 15 2016 11:07
{ a: 1,
  'b.c': 3,
  'd.e.f': 6,
  'd.g.0.h': 8,
  'd.g.0.i': 9,
  'd.g.1': 0 }
Kurt Milam
@kurtmilam
Aug 15 2016 11:08
Nice! More concise + additional functionality.
although it seems to be confused, having prefixed 'g' with 'd'.
Scott Christopher
@scott-christopher
Aug 15 2016 11:09
g is a member of d in {a:1, b:{c:3}, d:{e:{f:6}, g:[{h:8, i:9}, 0]}}
Kurt Milam
@kurtmilam
Aug 15 2016 11:11
You're right - I had meant to put 'g' outside of 'd', thus the confusion.
that's way more concise than my non-ramda function.
Scott Christopher
@scott-christopher
Aug 15 2016 11:15
I might throw it in the cookbook because I recall a couple of others asking for something similar recently.
Kurt Milam
@kurtmilam
Aug 15 2016 11:21
Good idea. Here's my current, non-ramda function in action. It does a couple of additional things I'd forgotten to mention.
Bravi
@Bravilogy
Aug 15 2016 11:21
@scott-christopher I was one of them :d
Kurt Milam
@kurtmilam
Aug 15 2016 11:24
I'm going to take the time to refactor mine from scratch into Ramda-style to get the exact functionality I need as well as the valuable practice it'll provide.
but I'll probably cheat a little and use yours as a guide when I'm feeling stumped.
Scott Christopher
@scott-christopher
Aug 15 2016 11:26
:D
I'm guessing this has something to do with Mongo, or some kind of document store db?
Kurt Milam
@kurtmilam
Aug 15 2016 11:27
@scott-christopher something like that. CouchDB is the actual target, and I'm working with JSON config documents.
Scott Christopher
@scott-christopher
Aug 15 2016 11:29
Right. I'd be interested to hear how it works out for you.
Morten Poulsen
@mspoulsen
Aug 15 2016 15:42

Hi guys, I keep running into this pattern:

let data = { a : 1, b : 2 };
const bar = x => 5 * x.a;
const foo = x => R.set(R.lensProp('c'), bar(x), x);
foo(data);

Is there a way to refactor out the x from function foo?

Brad Compton (he/him)
@Bradcomp
Aug 15 2016 15:58
@mspoulsen You can use converge for this, but it doesn't really help the readability of the code. You can also use assoc instead of the lens to avoid the need to wrap your call in R.set.
@ram-bot
var data = { a : 1, b : 2 };
var bar = x => 5 * x.a;
var foo = R.converge(R.assoc('c'), [bar, R.identity])
foo(data);
ram-bot
@ram-bot
Aug 15 2016 15:58
{ a: 1, b: 2, c: 5 }
Morten Poulsen
@mspoulsen
Aug 15 2016 16:07
@Bradcomp thanks! :thumbsup:
Rick Medina
@rickmed
Aug 15 2016 20:30
hello!
how can I implement this using compose/pipe?
Monad().chain(function(var1) {
  return Monad().chain(function(var2) {
    return var1 + var2
  });
});
Brad Compton (he/him)
@Bradcomp
Aug 15 2016 20:34
@rickmed Is your goal to apply a binary function to two values in containers?
Rick Medina
@rickmed
Aug 15 2016 20:37
mmm not sure what you mean (just learning fp sorry :) )
are you talking about something like ap or liftN?
Brad Compton (he/him)
@Bradcomp
Aug 15 2016 20:40
Yeah, I was going to suggest lift
Rick Medina
@rickmed
Aug 15 2016 20:41
so lift would apply them in parallel, right? what if I wanted to do it in sequence like with chain above?
Brad Compton (he/him)
@Bradcomp
Aug 15 2016 20:43
So when you say Monad() up above, are you instantiating an empty Monad, or just using it as a placeholder for a Monad that you've already created?
Rick Medina
@rickmed
Aug 15 2016 20:45
the second i guess, meaning, an instantiated monad, something like monad.of(something)
sorry let me edit the code
Monad.of(a).chain(function(var1) {
  return functor.of(a).map(function(var2) {
    return var1 + var2
  });
});
Brad Compton (he/him)
@Bradcomp
Aug 15 2016 20:49
Sorry, I am messing with a few things here...
http://goo.gl/rzmYOq
Rick Medina
@rickmed
Aug 15 2016 20:49
does that makes more sense?
Brad Compton (he/him)
@Bradcomp
Aug 15 2016 20:50
It does.
Rick Medina
@rickmed
Aug 15 2016 20:52
btw, what maybe library is that?
Brad Compton (he/him)
@Bradcomp
Aug 15 2016 20:52
I think you will need to use lift or ap in order to work with multiple wrapped values.
Ramda-fantasy
That, and Sanctuary (under namespace S) are included in the repl
Rick Medina
@rickmed
Aug 15 2016 20:53
got it, thanks!
cool
Brad Compton (he/him)
@Bradcomp
Aug 15 2016 20:54
I'm trying to get something working with this function:
const safeDiv = curry((a, b) => b === 0 ? Maybe.Nothing() : Maybe.of(a / b))
So we can get chain involved
Rick Medina
@rickmed
Aug 15 2016 21:01
my use case is something like: compose(fn1, fn2, fn3)
Brad Compton (he/him)
@Bradcomp
Aug 15 2016 21:01
Do they all operate on the same monad?
The problem with compose and pipe is that, after the innermost function, they expect a single parameter
I say problem, but really I just mean that's how they work
Rick Medina
@rickmed
Aug 15 2016 21:04
I need fn1 to have access to a variable in fn3
like if fn2 were a function between the monad and the functor in the example above
Brad Compton (he/him)
@Bradcomp
Aug 15 2016 21:07
So you need to have access to the scope of fn1 in fn3?
Rick Medina
@rickmed
Aug 15 2016 21:07
the other way around (compose runs from right to left, no?)
Brad Compton (he/him)
@Bradcomp
Aug 15 2016 21:08
Sorry, you're right
Brad Compton (he/him)
@Bradcomp
Aug 15 2016 21:13
compose won't get you there without other helper functions. You'll need to pass both values you need to fn1 from fn3. So you'll probably want to pass a pair out of fn3, then apply fn2 to one of the items in the pair, passing the other one through unchanged. converge might help.
Rick Medina
@rickmed
Aug 15 2016 21:19
let me check converse out
Rick Medina
@rickmed
Aug 15 2016 21:25
similar to lift, right?
got it, thank you! @Bradcomp
Brad Compton (he/him)
@Bradcomp
Aug 15 2016 21:28
Cool!
Sorry if I made things more confusing than needed
Rick Medina
@rickmed
Aug 15 2016 21:29
no! it was helpful!