Article: Writing Julia style multiple dispatch code in D
jmh530 via Digitalmars-d-announce
digitalmars-d-announce at puremagic.com
Fri Aug 25 13:54:05 PDT 2017
On Friday, 25 August 2017 at 16:01:27 UTC, data pulverizer wrote:
>
> Your wrapping strategy looks sensible though I would probably
> generate them all using string mixins.
See below. I haven't implemented the random variables yet, but
otherwise it seems to be working well. There is some trickiness
with deprecated stuff that I had to hard code, but other than
that it's pretty generic. Also, I think it is ignoring my check
to only include public/export stuff. Not sure why that is.
module distribAlt;
private template isMemberOf(alias T, string x)
{
import std.traits : hasMember;
enum bool isMemberOf = hasMember!(T, x);
}
private void hasMemberCheck(alias T, string x)()
{
static assert(isMemberOf!(T, x), T.stringof ~ " must have " ~
x ~" member to
call " ~ x ~ " function");
}
private string genStructInternals(string funcName, string
structName)()
{
import dstats.distrib;
import std.array : appender;
import std.algorithm.searching : endsWith;
enum spaces = " ";
auto aliasBuf = appender!string();
auto importBuf = appender!string();
enum string invName = "inv" ~ structName;
enum bool anyPDForPMF = false;
importBuf.put(spaces);
importBuf.put("import dstats.distrib : ");
foreach(member; __traits(allMembers, dstats.distrib))
{
static if (__traits(getProtection, member) == "public" ||
__traits(getProtection, member) == "export")
{
import std.algorithm.searching : startsWith,
findSplitAfter;
import std.string : toLower;
static if (startsWith(member, funcName))
{
enum string memberAfter = findSplitAfter(member,
funcName)[1];
enum string lowerMemberAfter =
toLower(memberAfter);
importBuf.put(member ~ ", ");
aliasBuf.put(spaces);
aliasBuf.put("alias " ~ lowerMemberAfter ~ " = "
~ member ~ ";");
aliasBuf.put("\n");
static if ((lowerMemberAfter == "pdf") ||
(lowerMemberAfter == "pmf"))
{
aliasBuf.put(spaces);
aliasBuf.put("alias density = " ~
lowerMemberAfter ~ ";");
aliasBuf.put("\n");
}
}
else static if (startsWith(member, invName))
{
enum string memberAfter = findSplitAfter(member,
invName)[1];
importBuf.put(member ~ ", ");
aliasBuf.put(spaces);
aliasBuf.put("alias i" ~ toLower(memberAfter) ~ "
= "
~ member ~ ";");
aliasBuf.put("\n");
}
}
}
if (endsWith(importBuf.data, ", "))
{
string importOut = importBuf.data[0 .. ($ - (",
".length))] ~";\n";
if (endsWith(aliasBuf.data, "\n"))
return importOut ~ aliasBuf.data[0 .. ($ -
("\n").length)];
else
assert(0, "No relevant functions in dstats.distrib");
}
else
{
assert(0, "No relevant functions in dstats.distrib");
}
}
private string toLowerFirst(string name)()
{
import std.string : toLower;
import std.conv : to;
string firstLetter = name[0].toLower.to!string;
return firstLetter ~ name[1 .. $];
}
private string toUpperFirst(string name)()
{
import std.string : toUpper;
import std.conv : to;
string firstLetter = name[0].toUpper.to!string;
return firstLetter ~ name[1 .. $];
}
private template GenDistStruct(string name)
{
const char[] GenDistStruct =
"///"~ "\n" ~
"struct " ~ toUpperFirst!(name) ~ "\n" ~
"{\n" ~
genStructInternals!(name, toUpperFirst!(name)) ~ "\n" ~
"}";
}
string GenDistStructs()
{
import dstats.distrib;
import std.array : appender;
import std.algorithm.searching : startsWith, endsWith,
canFind,
findSplitBefore,
findSplitAfter;
string[__traits(allMembers, dstats.distrib).length]
createdStructs;
size_t i;
auto structsBuf = appender!string();
foreach(member; __traits(allMembers, dstats.distrib))
{
static if (__traits(getProtection, member) == "public" ||
__traits(getProtection, member) == "export")
{
static if ((member.endsWith("PDF") ||
member.endsWith("PMF") ||
member.endsWith("CDF") ||
member.endsWith("CDFR")))
{
static if (member.endsWith("PDF"))
enum string memberBefore =
findSplitBefore(member, "PDF")[0];
else static if (member.endsWith("PMF"))
enum string memberBefore =
findSplitBefore(member, "PMF")[0];
else static if (member.endsWith("CDF"))
enum string memberBefore =
findSplitBefore(member, "CDF")[0];
else static if (member.endsWith("CDFR"))
enum string memberBefore =
findSplitBefore(member, "CDFR")[0];
static if (member.startsWith("inv"))
enum string newMember =
toLowerFirst!(findSplitAfter(memberBefore, "inv")[1]);
else
enum string newMember = memberBefore;
static if (member != "chiSqrCDF" &&
member != "chiSqrCDFR" &&
member != "invChiSqrCDFR" &&
member != "invChiSqCDFR")
//Deprecated: Easiest way I found to fix it
{
if (i == 0 ||
!(createdStructs[0 ..
i].canFind(newMember)))
{
structsBuf.put(GenDistStruct!newMember);
structsBuf.put("\n");
createdStructs[i] = newMember;
i++;
}
}
}
}
}
return structsBuf.data;
}
mixin(GenDistStructs());
private template GenDistFunc(string name)
{
const char[] GenDistFunc =
"auto " ~ name ~ "(alias T, U...)(U u)\n" ~
"{\n" ~
` hasMemberCheck!(T, "` ~ name ~ `");` ~ "\n" ~
" return T." ~ name ~ "(u);\n" ~
"}";
}
mixin(GenDistFunc!("pdf"));
mixin(GenDistFunc!("pmf"));
mixin(GenDistFunc!("cdf"));
mixin(GenDistFunc!("cdfr"));
mixin(GenDistFunc!("icdf"));
mixin(GenDistFunc!("density"));
void main()
{
import std.stdio : writeln;
writeln(Normal.cdf(0.5, 0.0, 1.0));
writeln(cdf!Normal(0.5, 0.0, 1.0));
writeln(icdf!Normal(cdf!Normal(0.5, 0.0, 1.0), 0.0, 1.0));
writeln(LogNormal.cdf(0.5, 0.0, 1.0));
writeln(cdf!LogNormal(0.5, 0.0, 1.0));
}
More information about the Digitalmars-d-announce
mailing list