On Sunday, 25 October 2015 at 06:22:51 UTC, TheFlyingFiddle wrote:
On Sunday, 25 October 2015 at 05:45:15 UTC, Nerve wrote:
On Sunday, 25 October 2015 at 05:05:47 UTC, Rikki Cattermole
wrote:
Since I have no idea what the difference between Some(_),
None and default. I'll assume it's already doable.
_ represents all existing values not matched. In this case,
Some(_) represents any integer value that is not 7. None
specifically matches the case where no value has been
returned. We are, in most languages, also able to unwrap the
value:
match x {
Some(7) => "Lucky number 7!",
Some(n) => "Not a lucky number: " ~ n,
None => "No value found"
}
You can do something very similar to that. With slightly
different syntax.
import std.traits;
import std.conv;
import std.variant;
struct CMatch(T...) if(T.length == 1)
{
alias U = typeof(T[0]);
static bool match(Variant v)
{
if(auto p = v.peek!U)
return *p == T[0];
return false;
}
}
auto ref match(Handlers...)(Variant v)
{
foreach(handler; Handlers)
{
alias P = Parameters!handler;
static if(P.length == 1)
{
static if(isInstanceOf!(CMatch, P[0]))
{
if(P[0].match(v))
return handler(P[0].init);
}
else
{
if(auto p = v.peek!(P[0]))
return handler(*p);
}
}
else
{
return handler();
}
}
assert(false, "No matching pattern");
}
unittest
{
Variant v = 5;
string s = v.match!(
(CMatch!7) => "Lucky number seven",
(int n) => "Not a lucky number: " ~ n.to!string,
() => "No value found!");
writeln(s);
}
You could also emulate constant matching using default parameters
(albeit with the restriction that they must be after any
non-default/constant parameters), since the defaults form part of
the function's type. I tried making something like this earlier
this summer and it'd check that a given value was first equal to
the default parameter and match if so, or match if there was no
default parameter but the types matched.
e.g.
//template ma(tch/g)ic
unittest
{
Algebraic!(string, int, double, MyStruct) v = 5;
string s = v.match!(
(string s = "") => "Empty string!",
(string s) => s,
(int i = 7) => "Lucky number 7",
(int i = 0) => "Nil",
(int i) => i.to!string,
(double d) => d.to!string,
(MyStruct m = MyStruct(15)) => "Special MyStruct value",
(MyStruct m) => m.name, //
() => "ooer");
writeln(s);
}
It's a bit ugly overloading language features like this, but it
makes the syntax a little prettier.
I'd really like to see proper pattern matching as a
language-level feature however; for all the emulating it we can
do in D, it's not very pretty or friendly and optimising it is
harder since the language has no concept of pattern matching.
Things like Option (and other ADTs) are lovely, but really need
good pattern matching to become worthwhile IMO (e.g. Java
Optional<T> has a get() method that throws on empty, which
undermines the main reason to use optional - to have a guarantee
that you handle the empty case gracefully; Scala's Option is
really nice on the other hand since you can/should pattern match).