0

I was doing some functional programming practice with javascript lambda expressions and came up with the following code. The code aims to return a function that calculates given number's power of given base value. My code as follows;

const findUpper = base => (num, i = 0) => {
  if (num < base) {
    return i;
  } else {
    i++;
    return findUpper(Math.round(num / base), i);
  }
}

const findUpper2 = findUpper(2)
console.log(findUpper2(8)) //expected to have 3

The problem here is, recursion becomes broken after first findUpper call, because it returns a function.

How can I make this snippet work?

2
  • How does the non-curried function look like? Commented Nov 2, 2017 at 22:25
  • Just to show you the expressiveness of functions, take a look at the U/Y combinator Commented Nov 3, 2017 at 8:40

2 Answers 2

3

One way is like this

    var findUpper = base => {
        let fn = (num, i = 0) => {
            if (num < base) {
                return i;
            } else {
                i++;
                return fn(Math.round(num / base), i);
            }
        };
        return fn;
    }
    var findUpper2 = findUpper(2)
    console.log(findUpper2(8))

Declare the recursive function with a name inside fundUpper ... recursively call fn rather than findUpper

it's slightly "tidier" without using arrow functions needlessly

var findUpper = base => {
    return function fn(num, i = 0) {
        if (num < base) {
            return i;
        } else {
            i++;
            return fn(Math.round(num / base), i);
        }
    };
}
var findUpper2 = findUpper(2)
console.log(findUpper2(8))

Although, using => the code can be as simple as

const findUpper = base => {
    let fn = (num, i = 0) => (num < base) ? i : fn(Math.round(num / base), i + 1);
    return fn;
}
Sign up to request clarification or add additional context in comments.

3 Comments

A named function makes recursion possible. You are right about not using arrow functions needlessly. Thanks!
by the way, I'd be more inclined, in the first and last example, to return num => fn(num); - ensuring the "validity" of i :p
@UğurcanŞengit a named function is not required for recursion
0

Here's your mistake

i++
return findUpper(Math.round(num / base), i);

You intended:

// don't forget, findUpper is a curried function
return findUpper(Math.round(num/base))(i + 1);

Here's another way to write your program as a pure expression

const findUpper = (base = 1) => (num = 0, exp = 0) =>
  num < base
    ? exp
    : findUpper (base) (num / base, exp + 1)
    
console.log (findUpper (2) (8))

Using generic loop/recur procedures, we keep findUpper's parameters clean, increase loop performance, and maintain the curried interface you want

const recur = (...values) =>
  ({ recur, values })
  
const loop = f =>
{
  let acc = f ()
  while (acc && acc.recur === recur)
    acc = f (...acc.values)
  return acc
}

const findUpper = (base = 1) => (num = 0) =>
  loop ((n = num, exp = 0) =>
    n < base
      ? exp
      : recur (n / base, exp + 1))

console.log (findUpper (2) (8))

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.