-1

Just started using Ramda today in an attempt to learn/incorporate functional programming into my code by being more declarative, but I'm having trouble figuring out how to make this a bit more streamlined using pipes (or curry?) This is only used once so maybe I'm trying to hard.

Can anyone provide an explanation on how to trim this down so it looks less chaotic so I can get my head around FP? I seem to be only able to do this if I separate out each method and invoke separately like in the working example. The example was simplified for brevity.

Working Example

const logLevels: string[] = ['log', 'info', 'debug', 'error'];

// maps logLevels into pairs: [[log: f(x)], ['info': f(x)], ...]
const toPairs = (logLevel: string) => [logLevel, debug(`${process.env.APP_NAME}:${namespace}:${logLevel}`)];
const loggers: any = R.map(toPairs, logLevels);

// Then takes the pairs and makes it an object
// Output: { log: f(x), info: f(x), debug: f(x), ...}
this.debugger = R.fromPairs(loggers);

// Example Usage:
// this.debugger.log('...');
mtpultz
  • 17,267
  • 22
  • 122
  • 201
  • Looks like you might've solved it yourself, but in future consider giving the expected output as well as the usage. The first time reading it I wasn't clear you wanted to create a bunch of methods on `this.debugger` – Ross Mackay Oct 04 '17 at 10:29
  • Why did I get a -1 on this question? The question had an example of what I was working on and only asks how to take it from 4 separate lines down to something using pipes. I already stated that the example in the question works, but I didn't understand how to make it more efficient since I'm new to FP – mtpultz Oct 04 '17 at 20:09
  • @RossMackay I'm not sure how you misunderstood this question. I only asked how to take my `working example` (as in it works already, but in 4 parts) and make it less chaotic using pipes or other FP method. I thought the example of the array pairs above `toPairs` and the usage of `this.debugger` at the end would be enough, but for clarity even though the example usage is `this.debugger.log(...)` I've added the output that was being placed into `this.debugger` – mtpultz Oct 04 '17 at 20:26
  • To be clear the -1 wasn't me, but what I was looking for was the example output you added. The misunderstanding came from the binding of the function to `this.debugger`, which has nothing to do with what the function should output. – Ross Mackay Oct 04 '17 at 21:38

2 Answers2

1

I would do this with a reduce:

const logLevels = ['log', 'info', 'debug', 'error'];
const debugger = reduce(
  (dbg, level) => assoc(
    level, 
    debug(`${process.env.APP_NAME}:${namespace}:${level}`),
    dbg
  ), {}, logLevels)

debugger.info('hello, world')

You can see this in action on the Ramda REPL, where I had to change the name from debugger because that's reserved in the browser.

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
  • Thanks the REPL link I played with this a bit to figure out how it works. Would you ever break this apart so it self-documents a bit more, or is this pretty typical for what you would normally expect in FP? – mtpultz Oct 04 '17 at 20:59
  • Also, does it matter that `APP_NAME` and `namespace` aren't passed in making the function impure? Is the aim to have pure functions all the time, or because this isn't reused that's okay? – mtpultz Oct 04 '17 at 21:43
  • 1
    I might pull out a function to write it as `reduce(addDebuggerMethod, {}, log levels) `, but I mozt likely wouldn't bother as it is still readable to me, and I'm not likely to refuse that function. – Scott Sauyet Oct 05 '17 at 02:19
  • 1
    You have to draw your own lines about where to allow impurities. Almost certainly your program will have some (IO anyone?) I like to try to keep them to the edges of the system and leave the core pure. But a `debug` object is almost certainly not going to be pure anyway, so I'm less likely to be concerned about it here. – Scott Sauyet Oct 05 '17 at 02:25
0

Got pipes working after I noticed that the Ramda API makes the parameter passed into the pipe the second parameter in chained methods ie. R.map and not the first parameter like Elixir, which I was playing with this weekend as an introduction:

const logLevels = ['log', 'info', 'debug', 'error'];
const toPairs = (logLevel: string): any => [logLevel,
this.debugger = R.pipe(R.map(toPairs), R.fromPairs)(logLevels);

If anyone has any other suggestions I'm all ears :)

mtpultz
  • 17,267
  • 22
  • 122
  • 201