Display 100 Hello World Without Using Loops
ajibanda.com
ajibanda.com
Why not take it further and produce a more general solution?
In JavaScript I'd write something like this:
function recurseBetween(start, end, callback) {
// Create a recursive function
// which checks the limits and calls the supplied callback
var recursiveCallback = function(i) {
// Call the original callback
callback(i);
// If we're at the end, stop
if(i >= end) {
return;
} else {
// Else increment and recurse
recursiveCallback(++i);
}
};
// Start recursing with the start value
recursiveCallback(start);
}
Now you can use recurseBetween almost exactly as you would a for loop: recurseBetween(1, 10, function(i) {
console.log(i);
});
You could even abstract the start and max arguments as callbacks, and you could supply a callback to perform the increment too so that you're not limited to integral addition. function recurseBetween(initial, hasEnded, modify, callback) {
// Overwrite the callback with a recursive version:
var recursiveCallback = function(i) {
// Call the original callback
callback(i);
// If we're at the end, stop
if(hasEnded(i)) {
return;
} else {
// Else increment and recurse
recursiveCallback(modify(i));
}
};
// Start recursing with the start value
recursiveCallback(initial());
}
Which transforms our for loop example to: recurseBetween(function() {
return 1;
}, function(i) {
return i<=10;
}, function(i) {
return i++;
}, function(i) {
console.log(i);
});
Which at first glance is unwieldy, but gives complete control to the calling script, such that we could do things like introduce a step: recurseBetween(function() {
return 1;
}, function(i) {
return i<=100;
}, function(i) {
return i+=10;
}, function(i) {
console.log(i);
});
Or even more exotic things.In reality, this syntax is too complicated. I would probably introduce some helpers; eg you could pass in a straight integer or a function and it would deal with it. I'd also probably send the arguments as named parameters so the syntax looked like this instead:
recurseBetween({
'start': 1,
'end': 100,
'modify': function(i) {
return i+=10;
},
'callback': function(i) {
console.log(i);
}
});
Which is a little clearer. Obviously the example is somewhat contrived because in reality you'd just use a for loop! But an interesting exercise nonetheless. (define (unfold p f g seed)
(if (p seed)
'()
(cons (f seed) (unfold p f g (g seed)))))
And how you would call it to print "Hello world!" 100 times: (unfold (lambda (x) (> x 100))
(lambda (x) (display "Hello world"))
(lambda (x) (+ x 1))
1)
'p' is your predicate. It determines when to stop unfolding. It takes the current value ('seed') and returns a boolean that's True when you're done. It's your 'hasEnded'.'f' is what to do for each 'seed' value. In this case, it ignores the current value and just prints "Hello world". It's your 'callback'.
'g' maps each 'seed' value to the next 'seed' value. It's your 'modify'.
'seed' is the initial state for the unfold. It's your 'initial'.
-----
There are a couple other caveats to do with this being an expression rather than a statement, but it doesn't really matter right now. There are a million other cool things about unfolds (and folds, and other higher-order functions), but I'm not sure I could conscionably point you in the right direction since they lead to dangerous places.
Speaking of which, here is an unfold in Haskell, where it may (may) be clearer:
unfold p f g seed | p seed = []
| otherwise = x:xs
where
x = f seed
xs = unfold p f g (g seed)
sequence_ $ unfold (>100) (const $ print "Hello world!") (+1) 1
I say 'an' unfold, because there are a whole bunch of cool ways to do it (and some of them look nothing like this).If you must code a loop without using "for" it means you're doing a homework ;)
It's not used like that in C, it's definitely used like that in Erlang.
No loop, and no conditional recursion.
The flaw is to use arithmetic on stack function pointer, which is not recommended nor strictly defined.
Unrolling loops can be a good thing when optimizing code, but you can't get much worse than tail recursion. It's always a win to eliminate this code pattern. The order of complexity is the same, but your stack will blow up for large N.
I don't know what you're looking for when posing this problem. A simple loop is already the most efficient technique.
loop good tail recursion bad
Of course, this is just a homework quiz, right?
In C++, make the compiler do your recursion:
#include <iostream>
template <int N>
void pr(const std::string &msg)
{
std::cout << msg << std::endl;
pr<N-1>(msg);
}
template <>
void pr<0>(const std::string &msg)
{
}
int main(int argc, char *argv[])
{
pr<100>("Hello World");
return 0;
}#include <iostream>
using namespace std;
class HelloWorld {
public:
HelloWorld();
};HelloWorld::HelloWorld()
{
cout << "Hello World\n";
}int _tmain(int argc, _TCHAR* argv[])
{
HelloWorld * hi = new HelloWorld[100] ();
return 0;
}eval(Array(101).join('console.log("hello world");'));
I'm just sayin'.
replicateM_ 100 $ print "Hello World!"
It's pretty to me, damnit.-----
[0] http://hackage.haskell.org/packages/archive/base/latest/doc/...
sequence_ $ take 100 $ repeat $ putStrLn "Hello, World"
alternatively, mapM_ putStrLn $ take 100 $ repeat "Hello, World" [see above] mapM f xs = sequence (map f xs)
replicateM n x = sequence (replicate n x)
Another cool thing replicateM is equivalent to: for lists, it's the cartesian power (sequence is the cartesian product). ...this is actually the primary reason I'm aware of it.print implode(PHP_EOL, array_fill(1, 100, "Hello World"));
exec "print 'Hello world'\n" * 100Btw at interview time this solution would not be acceptable, because you are using still a built-in language construct for looping.
That... makes no sense, the code is not looping anywhere.
And if you could somehow disqualify this bit, then recursion most definitely wouldn't qualify.
How do you know the __mul__ operator overload for string is implemented with iteration?
It is not operator overloading in the strictest sense, but more of duck typing. In Python (and Ruby), operators are syntactic sugar for method calls on the first operand.
Operator overloading on the contrary suggests a function add(a, b) that reacts differently through polymorphism (i.e according to the types of its arguments).
The distinction is important as overloading and polymorphism simply do not exist in Ruby and Python, only overriding.
Rather than asking the interview candidate to use recursion for a problem that shouldn't be solved using recursion (unless in a language where recursion is the idiomatic iteration method), it would be better to ask about a problem that is best solved using recursion rather than printing "Hello world" -- perhaps something from Project Euler (http://projecteuler.net/).
Yes, there is chance that arbitrary objects can provide different semantics for __mul__. It would be true for any language.
print '\n'.join(['Hello world'] * 100)
No need for exec. print "Hello, World\n" * 100
No need for join either, and ends with a newline print "Hello world\n"*100
Would have worked just fine. for i in xrange(100):
statement
into: exec "statement" * 100
The 'no exec' alternatives propose something not as generic since they can only print something a number of times. print "Hello world\n" * 100 def print_many(n):
print("hello, world\n" * n)
Though the `exec` option given above certainly is... interesting. :) print ('hello, world\n' * 100)[:-1]perl -e 'print "Hello world\n" x 100;'
or
map { print "hello, world\n" } (1..100);
or a goto or maybe even disgusting abuse of try/catch
Depending on how far I wanted to tweak the interviewer's nose. :D
Prelude> take 100 $ cycle "Hello World"