0

I was doing a question on CodeWars and practicing some functional programming when I encountered a problem while trying to apply a function to a value.

So I made a pass() function that accepts a function as an argument so that I could use an anonymous function to manipulate that value and then return it. So, in this case, it takes the value from reduce and passes it to a function so it can manipulate that value then return it.

It WORKS but I really don't want to add a method to the Object prototype!

How can I do this another way while still maintaining the chaining of functions?

Simple Example

Object.prototype.pass = function(fn) {
  return fn(this);
};

var value = 1;

var new_value = value.pass(function(num){
   return num + 1;
});

console.log(value, new_value); // Outputs: 1 2

CodeWars Problem for context

Object.prototype.pass = function(fn) {
  return fn(this)
};

function digPow(n, p) {
  return n
    .toString()
    .split('')
    .reduce(function(total, num, i) {
      return total + Math.pow(parseInt(num), (p + i))
    }, 0)
    .pass(function(total) {
      return (total % n == 0) ? Math.floor(total / n) : -1;
    });
}

//digPow(89, 1) should return 1 since 8¹ + 9² = 89 = 89 * 1
console.log("Test Case 1 returns (", digPow(89, 1), ") should return 1")

//digPow(92, 1) should return -1 since there is no k such as 9¹ + 2² equals 92 * k
console.log("Test Case 2 returns (", digPow(92, 1), ") should return -1")

//digPow(695, 2) should return 2 since 6² + 9³ + 5⁴= 1390 = 695 * 2
console.log("Test Case 3 returns (", digPow(695, 2), ") should return 2")

//digPow(46288, 3) should return 51 since 4³ + 6⁴+ 2⁵ + 8⁶ + 8⁷ = 2360688 = 46288 * 51
console.log("Test Case 4 returns (", digPow(46288, 3), ") should return 51")

Code Wars Instructions

Some numbers have funny properties. For example:

89 --> 8¹ + 9² = 89 * 1

695 --> 6² + 9³ + 5⁴= 1390 = 695 * 2

46288 --> 4³ + 6⁴+ 2⁵ + 8⁶ + 8⁷ = 2360688 = 46288 * 51 Given a positive integer n written as abcd... (a, b, c, d... being digits) and a positive integer p we want to find a positive integer k, if it exists, such as the sum of the digits of n taken to the successive powers of p is equal to k * n. In other words:

Is there an integer k such as : (a ^ p + b ^ (p+1) + c ^(p+2) + d ^ (p+3) + ...) = n * k If it is the case we will return k, if not return -1.

Note: n, p will always be given as strictly positive integers.

1
  • There's no good reason to use method chaining in functional programming. Commented Apr 10, 2017 at 21:11

2 Answers 2

2

The solution is just to not use method chaining - the functionality you want to apply to the result is not a method of it. There are various ways around:

  • A simple variable:

    function digPow(n, p) {
      const total = n
        .toString()
        .split('')
        .reduce(function(total, num, i) {
          return total + Math.pow(parseInt(num), (p + i))
        }, 0);
      return (total % n == 0) ? Math.floor(total / n) : -1;
    }
    
  • An IIFE call (this approach works better with static functions):

    function digPow(n, p) {
      return (function(total) {
        return (total % n == 0) ? Math.floor(total / n) : -1;
      }(n
        .toString()
        .split('')
        .reduce(function(total, num, i) {
          return total + Math.pow(parseInt(num), (p + i))
        }, 0));
    }
    
  • The experimental bind operator (works better with static "methods" as well):

    function digPow(n, p) {
      return n
        .toString()
        .split('')
        .reduce(function(total, num, i) {
          return total + Math.pow(parseInt(num), (p + i))
        }, 0)
        :: function() {
          return (this % n == 0) ? Math.floor(this / n) : -1;
        }();
    }
    

You also could use any of the approaches with your pass "method".

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your quick Reply :D, The bind operator looks interesting.
2

You could also use the Identity functor. This gives you a chainable interface but doesn't touch native prototypes

const Identity = x => ({
  runIdentity: x,
  map: f => Identity(f(x))
})

const digPow = (n, p) =>
  Identity(n)
    .map(n => n.toString())
    .map(str => str.split(''))
    .map(nums => nums.reduce((total, num, i) =>
      total + Math.pow(parseInt(num, 10), p + i), 0))
    .map(total => total % n === 0 ? Math.floor(total / n) : -1)
    .runIdentity

console.log(digPow(89, 1))  // 1
console.log(digPow(695, 2)) // 2


If you define some reusable functions, it cleans up the code a little bit

const Identity = x => ({
  runIdentity: x,
  map: f => Identity(f(x))
})

const split = x => str => str.split(x)
const reduce = f => y => xs => xs.reduce(f, y)

const digPow = (n, p) =>
  Identity(n)
    .map(String)
    .map(split(''))
    .map(reduce((acc, x, i) => acc + Math.pow(Number(x), p + i)) (0))
    .map(x => x % n === 0 ? Math.floor(x / n) : -1)
    .runIdentity

console.log(digPow(89, 1))  // 1
console.log(digPow(695, 2)) // 2

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.