Re: static switch/pattern matching

2016-06-25 Thread John via Digitalmars-d-learn
On Saturday, 25 June 2016 at 12:35:39 UTC, Lodovico Giaretta 
wrote:
On Saturday, 25 June 2016 at 12:30:22 UTC, Lodovico Giaretta 
wrote:
If you want this to work, you need your lambdas to take the 
casted value as a parameter:




Thanks.



Re: static switch/pattern matching

2016-06-25 Thread Lodovico Giaretta via Digitalmars-d-learn
On Saturday, 25 June 2016 at 12:30:22 UTC, Lodovico Giaretta 
wrote:
If you want this to work, you need your lambdas to take the 
casted value as a parameter:


   void test(T)(T value) {
 int i;
 string s;
 match!(value,
   int, (val) => i = val,
   string, (val) => s = val
 );
   }

And of course you need to modify match! for this to work.


Something like this:

   void match(alias t, cases...)() {
 static if (cases.length == 1) cases[0]();
 else static if (cases.length > 2) {
   static if (is(typeof(cases[0]) == bool)) {
 static if (cases[0]) cases[1](t);
 else match!(t, cases[2 .. $]);
   }
   else static if (is(typeof(t) == cases[0])) cases[1](t);
   else match!(t, cases[2 .. $]);
 }
   }

   void test(T)(T value) {
 int i;
 string s;
 match!(value,
   int, (val) => i = val,
   string, (val) => s = val
 );
   }

   void main()
   {
 test(1);
 test("A string");
   }


Re: static switch/pattern matching

2016-06-25 Thread Lodovico Giaretta via Digitalmars-d-learn

On Saturday, 25 June 2016 at 10:39:09 UTC, John wrote:
Thanks for the help, both. This appeared to work, until I 
realised the lambda isn't static:


  void match(T, cases...)() {
static if (cases.length == 1) cases[0]();
else static if (cases.length > 2) {
  static if (is(typeof(cases[0]) == bool)) {
static if (cases[0]) cases[1]();
else match!(T, cases[2 .. $]);
  }
  else static if (is(T == cases[0])) cases[1]();
  else match!(T, cases[2 .. $]);
}
  }

  void test(T)(T value) {
int i;
string s;
match!(T,
  int, () => i = value,
  string, () => s = value
);
  }

  test(1);
  test("A string");

The compiler complains about not being able convert an int to a 
string and vice versa.


If you want this to work, you need your lambdas to take the 
casted value as a parameter:


   void test(T)(T value) {
 int i;
 string s;
 match!(value,
   int, (val) => i = val,
   string, (val) => s = val
 );
   }

And of course you need to modify match! for this to work.


Re: static switch/pattern matching

2016-06-25 Thread John via Digitalmars-d-learn
On Saturday, 25 June 2016 at 09:12:12 UTC, Lodovico Giaretta 
wrote:
On Saturday, 25 June 2016 at 09:07:19 UTC, Lodovico Giaretta 
wrote:


Instead of passing functions to match!, pass pairs of 
arguments, like this:


match!(T,
int, writeln("Matched int"),
is(T : SomeObject), writeln("Derives from SomeObject");
);

Now, in the implementation, foreach pair of arguments, if the 
first member is a type that matches your target, perform that 
branch; otherwise, if the first member is a boolean value, and 
it is true, perform the branch.


Of course I meant:

 match!(T,
 int, () {writeln("Matched int");},
 is(T : SomeObject), () {writeln("Derives from 
SomeObject");}

 );



Thanks for the help, both. This appeared to work, until I 
realised the lambda isn't static:


  void match(T, cases...)() {
static if (cases.length == 1) cases[0]();
else static if (cases.length > 2) {
  static if (is(typeof(cases[0]) == bool)) {
static if (cases[0]) cases[1]();
else match!(T, cases[2 .. $]);
  }
  else static if (is(T == cases[0])) cases[1]();
  else match!(T, cases[2 .. $]);
}
  }

  void test(T)(T value) {
int i;
string s;
match!(T,
  int, () => i = value,
  string, () => s = value
);
  }

  test(1);
  test("A string");

The compiler complains about not being able convert an int to a 
string and vice versa.


Re: static switch/pattern matching

2016-06-25 Thread Lodovico Giaretta via Digitalmars-d-learn
On Saturday, 25 June 2016 at 09:07:19 UTC, Lodovico Giaretta 
wrote:


Instead of passing functions to match!, pass pairs of 
arguments, like this:


match!(T,
int, writeln("Matched int"),
is(T : SomeObject), writeln("Derives from SomeObject");
);

Now, in the implementation, foreach pair of arguments, if the 
first member is a type that matches your target, perform that 
branch; otherwise, if the first member is a boolean value, and 
it is true, perform the branch.


Of course I meant:

 match!(T,
 int, () {writeln("Matched int");},
 is(T : SomeObject), () {writeln("Derives from 
SomeObject");}

 );

You could probably even match on the actual value (instead of its 
type) and pass it (correctly casted) to the functions:


 match!(t,
 int, (int t) {writeln("Matched int ", t);},
 is(T : SomeObject), (SomeObject t) {writeln(t, " derives 
from SomeObject");}

 );

I don't have time to implement it now, but I think it's not too 
difficult.


Re: static switch/pattern matching

2016-06-25 Thread ketmar via Digitalmars-d-learn

also, there is a subtle bug in matcher. sorry. ;-)


Re: static switch/pattern matching

2016-06-25 Thread ketmar via Digitalmars-d-learn

On Saturday, 25 June 2016 at 08:46:05 UTC, John wrote:

Anyone able to improve on it?


q hack:

template tyma(T, Cases...) {
  import std.traits;
  template GetFunc(size_t idx) {
static if (idx >= Cases.length) {
  static assert(0, "no delegate for match");
} else static if (isCallable!(Cases[idx])) {
  enum GetFunc = Cases[idx];
} else {
  enum GetFunc = GetFunc!(idx+1);
}
  }
  template Matcher(size_t idx) {
//pragma(msg, "T=", T, "; idx=", idx, "; Cases[idx]=", 
Cases[idx], "; is=", is(typeof(T) == Cases[idx]));

static if (idx >= Cases.length) {
  static assert(0, "no match, consider adding `void` branch");
} else static if (isCallable!(Cases[idx])) {
  enum Matcher = Matcher!(idx+1);
} else static if (is(Cases[idx] == void)) {
  enum Matcher = GetFunc!(idx+1);
} else static if (is(typeof(Cases[idx]) == string)) {
  mixin("static if (is(T:"~Cases[idx]~")) enum Matcher = 
GetFunc!(idx+1); else enum Matcher = Matcher!(idx+1);");

} else static if (is(typeof(Cases[idx]))) {
  static assert(0, "unexpected something in cases: 
"~Cases[idx].stringof);

} else static if (is(T == Cases[idx])) {
  enum Matcher = GetFunc!(idx+1);
} else {
  enum Matcher = Matcher!(idx+1);
}
  }
  enum tyma = Matcher!0;
}


void main () {
  import std.stdio;
  auto res = tyma!(int,
string, () => "string",
"long", () => "integral",
void, () => "anything",
  )();
  writeln(res);
}


note that you should separate type names from labdas with "," 
instead of doing `int => "integral`, and have to add `()` at the 
end to actually call the delegate.


Re: static switch/pattern matching

2016-06-25 Thread Lodovico Giaretta via Digitalmars-d-learn

On Saturday, 25 June 2016 at 08:46:05 UTC, John wrote:
Writing a long series of "static if ... else" statements can be 
tedious and I'm prone to leaving out the crucial "static" after 
"else", so I was wondered if it was possible to write a 
template that would resemble the switch statement, but for 
types.


Closest I came up to was this:

  void match(T, Fs...)() {
foreach (F; Fs) {
  static if (isFunctionPointer!F) {
alias Ps = Parameters!F;
static if (Ps.length == 1) {
  static if (is(Ps[0] == T)) F(Ps[0].init);
}
  }
}
  }

  void test(T)(T t) {
match!(T,
  (int _) => writeln("Matched int"),
  (string _) => writeln("Matched string")
);
  }

But that's pretty limited and I'd like to be able to match on 
whether a type derives from T as well. I just can't figure it 
out.


Something like this would be ideal...

  match!(T,
int => writeln("Matched int"),
is(T : SomeObject) => writeln("Derives from SomeObject")
  );

Anyone able to improve on it?


Instead of passing functions to match!, pass pairs of arguments, 
like this:


match!(T,
int, writeln("Matched int"),
is(T : SomeObject), writeln("Derives from SomeObject");
);

Now, in the implementation, foreach pair of arguments, if the 
first member is a type that matches your target, perform that 
branch; otherwise, if the first member is a boolean value, and it 
is true, perform the branch.


static switch/pattern matching

2016-06-25 Thread John via Digitalmars-d-learn
Writing a long series of "static if ... else" statements can be 
tedious and I'm prone to leaving out the crucial "static" after 
"else", so I was wondered if it was possible to write a template 
that would resemble the switch statement, but for types.


Closest I came up to was this:

  void match(T, Fs...)() {
foreach (F; Fs) {
  static if (isFunctionPointer!F) {
alias Ps = Parameters!F;
static if (Ps.length == 1) {
  static if (is(Ps[0] == T)) F(Ps[0].init);
}
  }
}
  }

  void test(T)(T t) {
match!(T,
  (int _) => writeln("Matched int"),
  (string _) => writeln("Matched string")
);
  }

But that's pretty limited and I'd like to be able to match on 
whether a type derives from T as well. I just can't figure it out.


Something like this would be ideal...

  match!(T,
int => writeln("Matched int"),
is(T : SomeObject) => writeln("Derives from SomeObject")
  );

Anyone able to improve on it?