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)));
}

Reply via email to