3
\$\begingroup\$

Exercise 1: skips :: [a] -> [[a]]

The nth list in the output should contain every nth element from the input list. For example, skips "hello!" == ["hello!", "el!", "l!", "l", "o", "!"].

The question UPenn Homework 3: skips function and it's associated answers inspired me to write a solution in Javascript. I used the opportunity to (finally) better understand high order array functions. If you would be so kind to critique:

  1. Code Layout, specifically if nesting function skips() makes any sense and why.
  2. Do higher order functions provide more than just readability, are they more efficient?
  3. Can I make the nested function skips() better (readable/faster)?
  4. Anything at all.
function skip(str, cb) {
  var input = str.split('');

  cb(input.map(skips));

  function skips(val, index, arr) {
    var res = [];
    var i = index;
    var iterator = i + 1;
    for (i; i < arr.length; i += iterator){
      res.push(arr[i]);
    }
    return res;
  }
}

skip('hello!', console.log);
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

I agree with most of what @Dair said, but disagree with polluting the global namespace with a skipHelper() that is of little value to anyone else.

I'd also make a few tweaks to the helper:

  • It can be an anonymous function.
  • I'd call the first parameter _ to indicate that it is unused.
  • var i can be declared in the for loop header.
  • extracted would be a slightly more descriptive name than res.
function skips(str) {
    return str.split('').map(function(_, index, array) {
        var extracted = [];
        for (var i = index; i < array.length; i += 1 + index) {
            extracted.push(array[i]);
        }
        return extracted.join('');
    });
}
\$\endgroup\$
1
  • \$\begingroup\$ Thank you for the response. A follow up questions on your answer. Is there a benefit of using an anonymous function? \$\endgroup\$
    – boatSoap
    Commented Sep 8, 2015 at 16:40
2
\$\begingroup\$

Ok, first off: Passing in console.log as a paramater seems unnecessary. The function should have one task:

Generate the skips

Then once you have the skips you can do whatever you want with it. So:

function skip(str, cb) -> function skip(str)

and:

skip('hello!', console.log); -> console.log(skip('hello'));

I would also not use a function within a function. I would try keeping the functions relatively small. Split the functions:

function skipHelper(val, index, arr) {
  var res = [];
  var i = index;
  var iterator = i + 1;
  for (i; i < arr.length; i += iterator){
    res.push(arr[i]);
  }
  return res;
}

function skip(str) {
  var input = str.split('')
  return input.map(skips);
}

Also, given that str.split('') isn't too much to explicitly write out, change:

  var input = str.split('')
  return input.map(skips);

To just:

  return str.split('').map(skips);

Also, your code doesn't run exactly as described. Add a .join('') to return res; and this should fix it:

return res; -> return res.join('');

All in all:

function skipHelper(val, index, arr) {
  var res = [];
  var i = index;
  var iterator = i + 1;
  for (i; i < arr.length; i += iterator){
    res.push(arr[i]);
  }
  return res.join('');
}

function skip(str) {
  return str.split('').map(skipHelper);
}

console.log(skip('hello!'));

There are probably some Javascript language specific stylistic choices I am missing, but this is for general code structure.

\$\endgroup\$
1
  • \$\begingroup\$ Hello. Thank you for the response. Passing console.log is useless and it was used as a placeholder, your layout is much cleaner. I was attempting to model an async function. \$\endgroup\$
    – boatSoap
    Commented Sep 8, 2015 at 16:50

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.