On Thursday, 22 October 2015 at 13:53:33 UTC, pineapple wrote:
I'm just starting to hammer D's very pleasant syntax into my
head. After "Hello world", the first thing I do when learning
any language is to write a simple program which generates and
outputs the Collatz sequence for an arbitrary number. (I also
like to golf it.) This is what I wrote in D:
import std.stdio;void main(){int i;readf("
%d",&i);while(i>1){writeln(i=i%2?i*3+1:i/2);}}
Any ways I could shorten it further?
Anyway, then I thought I should try something that was less of
a mess, too, and wrote this:
import std.concurrency;
Generator!int sequence(int i){
return new Generator!int({
yield(i);
while(i > 1){
yield(i = (i % 2) ? (i * 3 + 1) : (i >> 1));
}
});
}
Which can be used like so:
import std.stdio;
void main(){
foreach(i; sequence(11)){
writeln(i);
}
}
And now I'd like to make one more improvement, but this I
haven't been able to figure out. What if I wanted the argument
and output types to be longs instead of ints? Or some other,
arbitrary discrete numeric type? Is there any template-like
syntax I can use here instead of just copypasting for each
numeric type I can think of? I've been spoiled by the likes of
Python to be thinking in this duck-typing way.
Thanks!
Using ranges instead of threads or fibers, slightly
over-engineered to show off features:
import std.traits : isIntegral;
auto collatzStep(T)(T i)
if(isIntegral!T)
{
return (i % 2) ? (i * 3 + 1) : (i >> 1);
}
auto collatz(T)(T a)
if(isIntegral!T)
{
import std.range : recurrence;
import std.algorithm : until, OpenRight;
return a.recurrence!((a, n) => collatzStep(a[n-1]))
.until!(n => n == 1)(OpenRight.no);
}
unittest
{
import std.algorithm : equal;
import std.range : only;
assert(collatz(6L).equal(only(6, 3, 10, 5, 16, 8, 4, 2, 1)));
}