Re: Allowing arbitrary types for a function's argument and return type

2015-10-22 Thread Kagamin via Digitalmars-d-learn

On Thursday, 22 October 2015 at 15:10:58 UTC, pineapple wrote:
What does if(isIntegral!T) do? It looks like it would verify 
that the template type is a discrete number?


It doesn't verify, but filters: you can have several templates 
with the same name, when filter doesn't match, compiler tries 
another template. Maybe you can write collatzStep for string 
type, then this code wouldn't compile, because it doesn't make 
sense for strings. Remove the filter and the template will always 
compile with whatever it's supplied including BigNum as long as 
the code makes sense.


Re: Allowing arbitrary types for a function's argument and return type

2015-10-22 Thread pineapple via Digitalmars-d-learn

On Thursday, 22 October 2015 at 13:58:56 UTC, Adam D. Ruppe wrote:
D's templates are easy (you actually used one in there, the 
Generator is one!)


Try this:

import std.concurrency;
Generator!T sequence(T)(T i){
return new Generator!T({
yield(i);
while(i > 1){
yield(i = (i % 2) ? (i * 3 + 1) : (i >> 1));
}
});
}


Wonderful, thanks much! It keeps surprising me how easy it is to 
do stuff like this.


Re: Allowing arbitrary types for a function's argument and return type

2015-10-22 Thread John Colvin via Digitalmars-d-learn

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


Allowing arbitrary types for a function's argument and return type

2015-10-22 Thread pineapple via Digitalmars-d-learn
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",);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!


Re: Allowing arbitrary types for a function's argument and return type

2015-10-22 Thread Adam D. Ruppe via Digitalmars-d-learn

On Thursday, 22 October 2015 at 13:53:33 UTC, pineapple wrote:

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?


D's templates are easy (you actually used one in there, the 
Generator is one!)


Try this:

import std.concurrency;
Generator!T sequence(T)(T i){
return new Generator!T({
yield(i);
while(i > 1){
yield(i = (i % 2) ? (i * 3 + 1) : (i >> 1));
}
});
}


The first set of args, `(T)`, are the template arguments. You can 
then use hat anywhere in teh function as a type placeholder.



Now, when you call it, it can automatically deduce the types:

 foreach(i; sequence(11)){ // still works, uses int
 foreach(i; sequence(11L)){ // also works, uses long now

Or you can tell your own args explicitly:

 foreach(i; sequence!long(11)){ // uses long



The pattern is name!(template, args, ...)(regular, args...)

The ! introduces template arguments. If there is just one simple 
argument - one consisting of a single word - you can leaves the 
parenthesis out.


Re: Allowing arbitrary types for a function's argument and return type

2015-10-22 Thread pineapple via Digitalmars-d-learn

On Thursday, 22 October 2015 at 14:36:52 UTC, John Colvin wrote:
Using ranges instead of threads or fibers, slightly 
over-engineered to show off features:


What does if(isIntegral!T) do? It looks like it would verify that 
the template type is a discrete number? If I were to create my 
own class, say a BigNum as an example, how could I specify that 
the isIntegral condition should be met for it?


Apart from the aesthetics, what are the functional differences 
between using recurrence and using a Generator? Will one be more 
efficient than the other?


It's not fair how easy it is to incorporate unit tests in D. Now 
what excuse will I have when my code is buggy?


Re: Allowing arbitrary types for a function's argument and return type

2015-10-22 Thread John Colvin via Digitalmars-d-learn

On Thursday, 22 October 2015 at 15:10:58 UTC, pineapple wrote:

On Thursday, 22 October 2015 at 14:36:52 UTC, John Colvin wrote:
Using ranges instead of threads or fibers, slightly 
over-engineered to show off features:


What does if(isIntegral!T) do? It looks like it would verify 
that the template type is a discrete number? If I were to 
create my own class, say a BigNum as an example, how could I 
specify that the isIntegral condition should be met for it?


Only with builtin types: 
http://dlang.org/phobos/std_traits.html#isIntegral
However there are a variety of ways you could mark special 
properties of types and have your own isIntegral-like template 
that recognised them. user-defined-attributes are one 
possibility, adding an `enum isIntegral = true;` is another.


Apart from the aesthetics, what are the functional differences 
between using recurrence and using a Generator? Will one be 
more efficient than the other?


ranges are likely to be more efficient because, apart from 
anything else, they are easier for the compiler to reason about 
and optimise. Both are good tools, but ranges are more widespread 
in D.


It's not fair how easy it is to incorporate unit tests in D. 
Now what excuse will I have when my code is buggy?


:)